Imported Upstream version 2.1.14 upstream/2.1.14
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:12 +0000 (16:00 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:12 +0000 (16:00 +0900)
278 files changed:
.gitignore
AUTHORS
NEWS
acinclude.m4
agent/command.c
agent/findkey.c
agent/protect.c
build-aux/config.guess
build-aux/config.sub
build-aux/speedo.mk
build-aux/speedo/w32/pkg-copyright.txt
common/Makefile.am
common/argparse.c
common/b64dec.c
common/b64enc.c
common/ccparray.c
common/exechelp-posix.c
common/exectool.c
common/gettime.c
common/gettime.h
common/init.c
common/iobuf.c
common/name-value.c [moved from common/private-keys.c with 79% similarity]
common/name-value.h [moved from common/private-keys.h with 56% similarity]
common/openpgpdefs.h
common/recsel.c [new file with mode: 0644]
common/recsel.h [new file with mode: 0644]
common/simple-pwquery.c
common/stringhelp.c
common/t-convert.c
common/t-gettime.c
common/t-iobuf.c
common/t-mbox-util.c
common/t-name-value.c [moved from common/t-private-keys.c with 69% similarity]
common/t-recsel.c [new file with mode: 0644]
common/t-stringhelp.c
common/t-strlist.c
common/util.h
common/zb32.c
configure.ac
dirmngr/http.c
dirmngr/ks-engine-hkp.c
dirmngr/ks-engine-http.c
dirmngr/server.c
dirmngr/t-ldap-parse-uri.c
doc/HACKING
doc/Makefile.am
doc/gpg-agent.texi
doc/gpg.texi
doc/mkdefsinc.c
doc/tools.texi
doc/yat2m.c
g10/armor.c
g10/build-packet.c
g10/card-util.c
g10/compress.c
g10/encrypt.c
g10/export.c
g10/free-packet.c
g10/getkey.c
g10/gpg.c
g10/gpgv.c
g10/import.c
g10/kbnode.c
g10/keydb.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keyid.c
g10/keylist.c
g10/keyserver.c
g10/main.h
g10/mainproc.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/pkclist.c
g10/plaintext.c
g10/revoke.c
g10/server.c
g10/sign.c
g10/t-keydb-get-keyblock.c
g10/t-keydb.c
g10/t-stutter.c
g10/tdbio.c
g10/test-stubs.c
g10/textfilter.c
g10/trustdb.c
g13/g13tuple.c
kbx/keybox-blob.c
m4/Makefile.am
m4/pkg.m4 [new file with mode: 0644]
po/ca.po
po/cs.po
po/da.po
po/de.po
po/el.po
po/eo.po
po/es.po
po/et.po
po/fi.po
po/fr.po
po/gl.po
po/hu.po
po/id.po
po/it.po
po/ja.po
po/nb.po
po/pl.po
po/pt.po
po/ro.po
po/ru.po
po/sk.po
po/sv.po
po/tr.po
po/uk.po
po/zh_CN.po
po/zh_TW.po
scd/ccid-driver.c
scd/scdaemon.c
tests/Makefile.am
tests/gpgscm/LICENSE.TinySCHEME [new file with mode: 0644]
tests/gpgscm/Makefile.am [new file with mode: 0644]
tests/gpgscm/Manual.txt [new file with mode: 0644]
tests/gpgscm/ffi-private.h [new file with mode: 0644]
tests/gpgscm/ffi.c [new file with mode: 0644]
tests/gpgscm/ffi.h [new file with mode: 0644]
tests/gpgscm/ffi.scm [new file with mode: 0644]
tests/gpgscm/init.scm [new file with mode: 0644]
tests/gpgscm/lib.scm [new file with mode: 0644]
tests/gpgscm/main.c [new file with mode: 0644]
tests/gpgscm/opdefines.h [new file with mode: 0644]
tests/gpgscm/private.h [new file with mode: 0644]
tests/gpgscm/repl.scm [new file with mode: 0644]
tests/gpgscm/scheme-config.h [new file with mode: 0644]
tests/gpgscm/scheme-private.h [new file with mode: 0644]
tests/gpgscm/scheme.c [new file with mode: 0644]
tests/gpgscm/scheme.h [new file with mode: 0644]
tests/gpgscm/t-child.c [new file with mode: 0644]
tests/gpgscm/t-child.scm [new file with mode: 0644]
tests/gpgscm/tests.scm [new file with mode: 0644]
tests/migrations/Makefile.am
tests/migrations/common.scm [new file with mode: 0644]
tests/migrations/extended-pkf.scm [new file with mode: 0755]
tests/migrations/extended-pkf.tar.asc [new file with mode: 0644]
tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc [deleted file]
tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc [deleted file]
tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc [deleted file]
tests/migrations/extended-private-key-format.gpghome/pubring.kbx.asc [deleted file]
tests/migrations/extended-private-key-format.gpghome/trustdb.gpg.asc [deleted file]
tests/migrations/extended-private-key-format.test [deleted file]
tests/migrations/from-classic.gpghome/pubring.gpg.asc [deleted file]
tests/migrations/from-classic.gpghome/secring.gpg.asc [deleted file]
tests/migrations/from-classic.gpghome/trustdb.gpg.asc [deleted file]
tests/migrations/from-classic.scm [new file with mode: 0755]
tests/migrations/from-classic.tar.asc [new file with mode: 0644]
tests/migrations/from-classic.test [deleted file]
tests/openpgp/4gb-packet.scm [new file with mode: 0755]
tests/openpgp/Makefile.am
tests/openpgp/README [new file with mode: 0644]
tests/openpgp/armdetach.scm [new file with mode: 0755]
tests/openpgp/armdetachm.scm [new file with mode: 0755]
tests/openpgp/armencrypt.scm [new file with mode: 0755]
tests/openpgp/armencryptp.scm [new file with mode: 0755]
tests/openpgp/armor.scm [new file with mode: 0755]
tests/openpgp/armsignencrypt.scm [new file with mode: 0755]
tests/openpgp/armsigs.scm [new file with mode: 0755]
tests/openpgp/clearsig.scm [new file with mode: 0755]
tests/openpgp/conventional-mdc.scm [new file with mode: 0755]
tests/openpgp/conventional.scm [new file with mode: 0755]
tests/openpgp/decrypt-dsa.scm [new file with mode: 0755]
tests/openpgp/decrypt.scm [new file with mode: 0755]
tests/openpgp/default-key.scm [new file with mode: 0755]
tests/openpgp/defs.scm [new file with mode: 0644]
tests/openpgp/detach.scm [new file with mode: 0755]
tests/openpgp/detachm.scm [new file with mode: 0755]
tests/openpgp/ecc.scm [new file with mode: 0755]
tests/openpgp/encrypt-dsa.scm [new file with mode: 0755]
tests/openpgp/encrypt.scm [new file with mode: 0755]
tests/openpgp/encryptp.scm [new file with mode: 0755]
tests/openpgp/export.scm [new file with mode: 0755]
tests/openpgp/finish.scm [new file with mode: 0755]
tests/openpgp/genkey1024.scm [new file with mode: 0755]
tests/openpgp/gpg-agent.conf.tmpl
tests/openpgp/gpgtar.scm [new file with mode: 0755]
tests/openpgp/import.scm [new file with mode: 0755]
tests/openpgp/mds.scm [new file with mode: 0755]
tests/openpgp/multisig.scm [new file with mode: 0755]
tests/openpgp/privkeys/1E28F20E41B54C2D1234D896096495FF57E08D18.asc [new file with mode: 0644]
tests/openpgp/privkeys/C6A6390E9388CDBAD71EAEA698233FE5E04F001E.asc [new file with mode: 0644]
tests/openpgp/privkeys/D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3.asc [new file with mode: 0644]
tests/openpgp/privkeys/EB33B687EB8581AB64D04852A54453E85F3DF62D.asc [new file with mode: 0644]
tests/openpgp/quick-key-manipulation.test [new file with mode: 0755]
tests/openpgp/run-tests.scm [new file with mode: 0644]
tests/openpgp/samplekeys/README
tests/openpgp/samplekeys/ed25519-cv25519-sample-1.asc [new file with mode: 0644]
tests/openpgp/samplekeys/rsa-rsa-sample-1.asc [new file with mode: 0644]
tests/openpgp/samplekeys/silent-running.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/clearsig-1-key-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/clearsig-2-keys-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/clearsig-2-keys-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-1-key-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-1-key-1.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-1-key-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-1-key-2.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-2-keys-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-2-keys-1.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-2-keys-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-2-keys-2.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-2-keys-hh-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-2-keys-hr-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/enc-2-keys-rh-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-2-keys-3.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-2-keys-3.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-2-keys-4.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-2-keys-4.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-1.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-2.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-3.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-3.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-4.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encsig-2-keys-4.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/encz0-1-key-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/encz0-1-key-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-1-key-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-1-key-1.sig [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-1-key-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-1-key-2.sig [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-2-keys-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-2-keys-1.sig [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-2-keys-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/sig-2-keys-2.sig [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-1-key-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-1-key-1.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-1-key-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-1-key-2.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-2-keys-1.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-2-keys-1.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-2-keys-2.asc [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-2-keys-2.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/signed-data-1.txt [new file with mode: 0644]
tests/openpgp/samplemsgs/signedz0-1-key-1.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/signedz0-1-key-2.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/signedz0-2-keys-1.gpg [new file with mode: 0644]
tests/openpgp/samplemsgs/signedz0-2-keys-2.gpg [new file with mode: 0644]
tests/openpgp/seat.scm [new file with mode: 0755]
tests/openpgp/setup.scm [new file with mode: 0755]
tests/openpgp/signencrypt-dsa.scm [new file with mode: 0755]
tests/openpgp/signencrypt.scm [new file with mode: 0755]
tests/openpgp/sigs-dsa.scm [new file with mode: 0755]
tests/openpgp/sigs.scm [new file with mode: 0755]
tests/openpgp/tofu.scm [new file with mode: 0755]
tests/openpgp/tofu.test
tests/openpgp/use-exact-key.scm [new file with mode: 0755]
tests/openpgp/verify.scm [new file with mode: 0755]
tests/openpgp/version.scm [new file with mode: 0755]
tools/Makefile.am
tools/call-dirmngr.c [new file with mode: 0644]
tools/call-dirmngr.h [new file with mode: 0644]
tools/gpg-connect-agent.c
tools/gpg-wks-client.c [new file with mode: 0644]
tools/gpg-wks-server.c [new file with mode: 0644]
tools/gpg-wks.h [new file with mode: 0644]
tools/gpgconf.c
tools/gpgtar-extract.c
tools/gpgtar-list.c
tools/gpgtar.c
tools/mime-maker.c [new file with mode: 0644]
tools/mime-maker.h [new file with mode: 0644]
tools/mime-parser.c [new file with mode: 0644]
tools/mime-parser.h [new file with mode: 0644]
tools/rfc822parse.h
tools/send-mail.c [new file with mode: 0644]
tools/send-mail.h [new file with mode: 0644]
tools/wks-receive.c [new file with mode: 0644]
tools/wks-util.c [new file with mode: 0644]

index dd3d031..4ae758f 100644 (file)
@@ -59,6 +59,8 @@ doc/faq.raw.xref
 doc/gnupg-card-architecture.eps
 doc/gnupg-card-architecture.pdf
 doc/gnupg-card-architecture.png
+doc/gnupg-module-overview.pdf
+doc/gnupg-module-overview.png
 doc/gnupg.7
 doc/gpg-agent.1
 doc/gpg-connect-agent.1
diff --git a/AUTHORS b/AUTHORS
index b192214..861258f 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -30,7 +30,7 @@ List of Copyright holders
   Copyright (C) 1999-2003 Symas Corporation.
   Copyright (C) 1998-2003 Hallvard B. Furuseth.
   Copyright (C) 1992-1996 Regents of the University of Michigan.
-
+  Copyright (C) 2000 Dimitrios Souflis
 
 
 Authors with a FSF copyright assignment
@@ -194,6 +194,9 @@ Stefan Tomanek <tomanek@internet-sicherheit.de>
 Werner Koch <wk@gnupg.org>
 2013-03-29:87620ahchj.fsf@vigenere.g10code.de:
 
+Yann E. MORIN <yann.morin.1998@free.fr>
+2016-07-10:20160710093202.GA3688@free.fr:
+
 
 Other authors
 =============
@@ -211,6 +214,10 @@ Alexandre Julliard.
 The gpg-zip documentation is based on the manpage for gpg-zip, written
 by Colin Tuckley and Daniel Leidert for the GNU/Debian distribution.
 
+The test driver is based on TinySCHEME by Dimitrios Souflis and
+available under a permissive license.  For the terms see the file
+tests/gpgscm/LICENSE.TinySCHEME.
+
 
 Copyright
 =========
diff --git a/NEWS b/NEWS
index 3c58883..cbf5f28 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,61 @@
+Noteworthy changes in version 2.1.14 (2016-07-14)
+-------------------------------------------------
+
+ * gpg: Removed options --print-dane-records and --print-pka-records.
+   The new export options "export-pka" and "export-dane" can instead
+   be used with the export command.
+
+ * gpg: New options --import-filter and --export-filter.
+
+ * gpg: New import options "import-show" and "import-export".
+
+ * gpg: New option --no-keyring.
+
+ * gpg: New command --quick-revuid.
+
+ * gpg: New options -f/--recipient-file and -F/--hidden-recipient-file
+   to directly specify encryption keys.
+
+ * gpg: New option --mimemode to indicate that the content is a MIME
+   part.  Does only enable --textmode right now.
+
+ * gpg: New option --rfc4880bis to allow experiments with proposed
+   changes to the current OpenPGP specs.
+
+ * gpg: Fix regression in the "fetch" sub-command of --card-edit.
+
+ * gpg: Fix regression since 2.1 in option --try-all-secrets.
+
+ * gpgv: Change default options for extra security.
+
+ * gpgsm: No more root certificates are installed by default.
+
+ * agent: "updatestartuptty" does now affect more environment
+   variables.
+
+ * scd: The option --homedir does now work with scdaemon.
+
+ * scd: Support some more GEMPlus card readers.
+
+ * gpgtar: Fix handling of '-' as file name.
+
+ * gpgtar: New commands --create and --extract.
+
+ * gpgconf: Tweak for --list-dirs to better support shell scripts.
+
+ * tools: Add programs gpg-wks-client and gpg-wks-server to implement
+   a Web Key Service.  The configure option --enable-wks-tools is
+   required to build them; they should be considered Beta software.
+
+ * tests: Complete rework of the openpgp part of the test suite.  The
+   test scripts have been changed from Bourne shell scripts to Scheme
+   programs.  A customized scheme interpreter (gpgscm) is included.
+   This change was triggered by the need to run the test suite on
+   non-Unix platforms.
+
+ * The rendering of the man pages has been improved.
+
+
 Noteworthy changes in version 2.1.13 (2016-06-16)
 -------------------------------------------------
 
@@ -214,7 +272,8 @@ Noteworthy changes in version 2.1.9 (2015-10-09)
 ------------------------------------------------
 
  * gpg: Allow fetching keys via OpenPGP DANE (--auto-key-locate).  New
-   option --print-dane-records.
+   option --print-dane-records.  [Update: --print-dane-records replaced
+   in 2.1.4.]
 
  * gpg: Fix for a problem with PGP-2 keys in a keyring.
 
@@ -368,7 +427,8 @@ Noteworthy changes in version 2.1.3 (2015-04-11)
  * gpg: New option --with-icao-spelling.
 
  * gpg: New option --print-pka-records.  Changed the PKA method to use
-   CERT records and hashed names.
+   CERT records and hashed names.  [Update: --print-pka-records
+   replaced in 2.1.4.]
 
  * gpg: New command --list-gcrypt-config.  New parameter "curve"
    for --list-config.
index 7c264a4..724c085 100644 (file)
@@ -165,23 +165,25 @@ AC_DEFUN([GNUPG_CHECK_ENDIAN],
 # build_NAME and whether --enable-NAME or --disable-NAME is shown with
 # ./configure --help
 AC_DEFUN([GNUPG_BUILD_PROGRAM],
-  [build_$1=$2
+  [m4_define([my_build], [m4_bpatsubst(build_$1, [[^a-zA-Z0-9_]], [_])])
+   my_build=$2
    m4_if([$2],[yes],[
       AC_ARG_ENABLE([$1], AC_HELP_STRING([--disable-$1],
                                          [do not build the $1 program]),
-                           build_$1=$enableval, build_$1=$2)
+                           my_build=$enableval, my_build=$2)
     ],[
       AC_ARG_ENABLE([$1], AC_HELP_STRING([--enable-$1],
                                          [build the $1 program]),
-                           build_$1=$enableval, build_$1=$2)
+                           my_build=$enableval, my_build=$2)
     ])
-   case "$build_$1" in
+   case "$my_build" in
          no|yes)
            ;;
          *)
            AC_MSG_ERROR([only yes or no allowed for feature --enable-$1])
            ;;
    esac
+   m4_undefine([my_build])
   ])
 
 
index de5b184..e5d2268 100644 (file)
@@ -2663,14 +2663,13 @@ static const char hlp_updatestartuptty[] =
 static gpg_error_t
 cmd_updatestartuptty (assuan_context_t ctx, char *line)
 {
-  static const char *names[] =
-    { "GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
   session_env_t se;
-  int idx;
   char *lc_ctype = NULL;
   char *lc_messages = NULL;
+  int iterator;
+  const char *name;
 
   (void)line;
 
@@ -2681,11 +2680,12 @@ cmd_updatestartuptty (assuan_context_t ctx, char *line)
   if (!se)
     err = gpg_error_from_syserror ();
 
-  for (idx=0; !err && names[idx]; idx++)
+  iterator = 0;
+  while (!err && (name = session_env_list_stdenvnames (&iterator, NULL)))
     {
-      const char *value = session_env_getenv (ctrl->session_env, names[idx]);
+      const char *value = session_env_getenv (ctrl->session_env, name);
       if (value)
-        err = session_env_setenv (se, names[idx], value);
+        err = session_env_setenv (se, name, value);
     }
 
   if (!err && ctrl->lc_ctype)
index d3780b9..c5ab0e9 100644 (file)
@@ -35,7 +35,7 @@
 #include "agent.h"
 #include "i18n.h"
 #include "../common/ssh-utils.h"
-#include "../common/private-keys.h"
+#include "../common/name-value.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -57,12 +57,12 @@ write_extended_private_key (char *fname, estream_t fp,
                             const void *buf, size_t len)
 {
   gpg_error_t err;
-  pkc_t pk = NULL;
+  nvc_t pk = NULL;
   gcry_sexp_t key = NULL;
   int remove = 0;
   int line;
 
-  err = pkc_parse (&pk, &line, fp);
+  err = nvc_parse_private_key (&pk, &line, fp);
   if (err)
     {
       log_error ("error parsing '%s' line %d: %s\n",
@@ -74,7 +74,7 @@ write_extended_private_key (char *fname, estream_t fp,
   if (err)
     goto leave;
 
-  err = pkc_set_private_key (pk, key);
+  err = nvc_set_private_key (pk, key);
   if (err)
     goto leave;
 
@@ -82,7 +82,7 @@ write_extended_private_key (char *fname, estream_t fp,
   if (err)
     goto leave;
 
-  err = pkc_write (pk, fp);
+  err = nvc_write (pk, fp);
   if (err)
     {
       log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
@@ -117,7 +117,7 @@ write_extended_private_key (char *fname, estream_t fp,
     gnupg_remove (fname);
   xfree (fname);
   gcry_sexp_release (key);
-  pkc_release (pk);
+  nvc_release (pk);
   return err;
 }
 
@@ -687,10 +687,10 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
   if (first != '(')
     {
       /* Key is in extended format.  */
-      pkc_t pk;
+      nvc_t pk;
       int line;
 
-      rc = pkc_parse (&pk, &line, fp);
+      rc = nvc_parse_private_key (&pk, &line, fp);
       es_fclose (fp);
 
       if (rc)
@@ -698,8 +698,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
                    fname, line, gpg_strerror (rc));
       else
         {
-          rc = pkc_get_private_key (pk, result);
-          pkc_release (pk);
+          rc = nvc_get_private_key (pk, result);
+          nvc_release (pk);
           if (rc)
             log_error ("error getting private key from '%s': %s\n",
                        fname, gpg_strerror (rc));
index ee08e57..68e4081 100644 (file)
 #include "sexp-parse.h"
 
 
-#if GCRYPT_VERSION_NUMBER < 0x010700
-# define OCB_MODE_SUPPORTED 0
-#else
-# define OCB_MODE_SUPPORTED 1
-#endif
-
 /* To use the openpgp-s2k3-ocb-aes scheme by default set the value of
  * this macro to 1.  Note that the caller of agent_protect may
  * override this default.  */
@@ -353,16 +347,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
   *resultlen = 0;
   *result = NULL;
 
-  if (use_ocb && !OCB_MODE_SUPPORTED)
-    return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
-
   modestr = (use_ocb? "openpgp-s2k3-ocb-aes"
              /*   */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
 
   rc = gcry_cipher_open (&hd, PROT_CIPHER,
-#if OCB_MODE_SUPPORTED
                          use_ocb? GCRY_CIPHER_MODE_OCB :
-#endif
                          GCRY_CIPHER_MODE_CBC,
                          GCRY_CIPHER_SECURE);
   if (rc)
@@ -500,7 +489,6 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
           p += blklen;
         }
       assert ( p - outbuf == outlen);
-#if OCB_MODE_SUPPORTED
       if (use_ocb)
         {
           gcry_cipher_final (hd);
@@ -512,7 +500,6 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
             }
         }
       else
-#endif /*OCB_MODE_SUPPORTED*/
         {
           rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
         }
@@ -755,9 +742,6 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
   unsigned char *outbuf;
   size_t reallen;
 
-  if (is_ocb && !OCB_MODE_SUPPORTED)
-    return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
-
   blklen = gcry_cipher_get_algo_blklen (prot_cipher);
   if (is_ocb)
     {
@@ -774,9 +758,7 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
     }
 
   rc = gcry_cipher_open (&hd, prot_cipher,
-#if OCB_MODE_SUPPORTED
                          is_ocb? GCRY_CIPHER_MODE_OCB :
-#endif
                          GCRY_CIPHER_MODE_CBC,
                          GCRY_CIPHER_SECURE);
   if (rc)
@@ -813,7 +795,6 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
   /* Decrypt.  */
   if (!rc)
     {
-#if OCB_MODE_SUPPORTED
       if (is_ocb)
         {
           rc = gcry_cipher_authenticate (hd, aad_begin,
@@ -833,7 +814,6 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
             rc = gcry_cipher_checktag (hd, protected + protectedlen - 16, 16);
         }
       else
-#endif /*OCB_MODE_SUPPORTED*/
         {
           rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
                                     protected, protectedlen);
@@ -1177,8 +1157,7 @@ agent_unprotect (ctrl_t ctrl,
         is_ocb = algotable[i].is_ocb;
         break;
       }
-  if (i == DIM (algotable)
-      || (is_ocb && !OCB_MODE_SUPPORTED))
+  if (i == DIM (algotable))
     return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
 
   if (!prot_cipher)  /* This is "openpgp-native".  */
index 0967f2a..c4bd827 100755 (executable)
@@ -2,7 +2,7 @@
 # Attempt to guess a canonical system name.
 #   Copyright 1992-2016 Free Software Foundation, Inc.
 
-timestamp='2016-04-02'
+timestamp='2016-05-15'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -186,9 +186,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
            *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
        esac
        # The Operating System including object format, if it has switched
-       # to ELF recently, or will in the future.
+       # to ELF recently (or will in the future) and ABI.
        case "${UNAME_MACHINE_ARCH}" in
-           arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
+           earm*)
+               os=netbsdelf
+               ;;
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
                eval $set_cc_for_build
                if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
                        | grep -q __ELF__
@@ -1408,18 +1411,17 @@ esac
 cat >&2 <<EOF
 $0: unable to guess system type
 
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
 
   http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 and
   http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <config-patches@gnu.org> in order to provide the needed
-information to handle your system.
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
 
 config.guess timestamp = $timestamp
 
index 8d39c4b..9feb73b 100755 (executable)
@@ -2,7 +2,7 @@
 # Configuration validation subroutine script.
 #   Copyright 1992-2016 Free Software Foundation, Inc.
 
-timestamp='2016-03-30'
+timestamp='2016-06-20'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -643,6 +643,14 @@ case $basic_machine in
                basic_machine=m68k-bull
                os=-sysv3
                ;;
+       e500v[12])
+               basic_machine=powerpc-unknown
+               os=$os"spe"
+               ;;
+       e500v[12]-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=$os"spe"
+               ;;
        ebmon29k)
                basic_machine=a29k-amd
                os=-ebmon
@@ -1389,7 +1397,7 @@ case $os in
              | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
              | -chorusos* | -chorusrdb* | -cegcc* \
              | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-             | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+             | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
              | -linux-newlib* | -linux-musl* | -linux-uclibc* \
              | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
              | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
@@ -1399,7 +1407,7 @@ case $os in
              | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
              | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
              | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
-             | -onefs* | -tirtos*)
+             | -onefs* | -tirtos* | -phoenix*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        -qnx*)
index 67ccbb4..fbe258c 100644 (file)
@@ -109,6 +109,10 @@ w32-release: check-tools
        $(SPEEDOMAKE) TARGETOS=w32 WHAT=release    WITH_GUI=0 SELFCHECK=0 \
                                                    installer-from-source
 
+w32-release-offline: check-tools
+       $(SPEEDOMAKE) TARGETOS=w32 WHAT=release    WITH_GUI=0 SELFCHECK=0 \
+         CUSTOM_SWDB=1 pkgrep=${HOME}/b pkg10rep=${HOME}/b  \
+         installer-from-source
 
 
 # Set this to "git" to build from git,
index 9495bcd..daf2881 100644 (file)
@@ -1,5 +1,5 @@
 Here is a list with collected copyright notices. For details see the
-description of each individual package.  [Compiled by wk 2016-04-20]
+description of each individual package.  [Compiled by wk 2016-06-17]
 
 GnuPG is
 
@@ -18,6 +18,7 @@ GnuPG is
   Copyright (C) 1999-2003 Symas Corporation.
   Copyright (C) 1998-2003 Hallvard B. Furuseth.
   Copyright (C) 1992-1996 Regents of the University of Michigan.
+  Copyright (C) 2000 Dimitrios Souflis
 
   GnuPG is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
@@ -111,6 +112,39 @@ ADNS is
   Copyright (C) 1991 Massachusetts Institute of Technology
 
 
+TinySCHEME is part of the GnuPG package and is
+
+  Copyright (c) 2000, Dimitrios Souflis
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+  Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+  Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+  Neither the name of Dimitrios Souflis nor the names of the
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
 SQLite has
 
   been put into the public-domain by its author D. Richard Hipp:
index 884c966..6f9d96d 100644 (file)
@@ -91,7 +91,8 @@ common_sources = \
        call-gpg.c call-gpg.h \
        exectool.c exectool.h \
        server-help.c server-help.h \
-       private-keys.c private-keys.h
+       name-value.c name-value.h \
+       recsel.c recsel.h
 
 if HAVE_W32_SYSTEM
 common_sources += w32-reg.c w32-afunix.c w32-afunix.h
@@ -157,7 +158,7 @@ module_tests = t-stringhelp t-timestuff \
                t-convert t-percent t-gettime t-sysutils t-sexputil \
               t-session-env t-openpgp-oid t-ssh-utils \
               t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
-              t-private-keys t-ccparray
+              t-name-value t-ccparray t-recsel
 if !HAVE_W32CE_SYSTEM
 module_tests += t-exechelp
 endif
@@ -206,8 +207,9 @@ t_zb32_LDADD = $(t_common_ldadd)
 t_mbox_util_LDADD = $(t_common_ldadd)
 t_iobuf_LDADD = $(t_common_ldadd)
 t_strlist_LDADD = $(t_common_ldadd)
-t_private_keys_LDADD = $(t_common_ldadd)
+t_name_value_LDADD = $(t_common_ldadd)
 t_ccparray_LDADD = $(t_common_ldadd)
+t_recsel_LDADD = $(t_common_ldadd)
 
 # System specific test
 if HAVE_W32_SYSTEM
index 00cde23..240fdce 100644 (file)
@@ -699,6 +699,8 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
                         }
                       if (!set_opt_arg (arg, opts[idx].flags, p))
                         xfree (buffer);
+                      else
+                        gpgrt_annotate_leaked_object (buffer);
                     }
                 }
               break;
index 3e02e4a..c84c35a 100644 (file)
@@ -1,29 +1,20 @@
 /* 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 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.
+ * 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 General Public License
+ * 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/>.
  */
 
@@ -61,7 +52,7 @@ static unsigned char const asctobin[128] =
 
 enum decoder_states
   {
-    s_init, s_idle, s_lfseen, s_begin,
+    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
   };
@@ -71,26 +62,18 @@ enum decoder_states
 /* 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.
-
-   Not yet implemented: If TITLE is either "PGP" or begins with "PGP "
-   the PGP armor lines are skipped as well.  */
+   seen, decoding ends at a "----END " line.  */
 gpg_error_t
 b64dec_start (struct b64state *state, const char *title)
 {
   memset (state, 0, sizeof *state);
   if (title)
     {
-      if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' '))
-        state->lasterr = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+      state->title = xtrystrdup (title);
+      if (!state->title)
+        state->lasterr = gpg_error_from_syserror ();
       else
-        {
-          state->title = xtrystrdup (title);
-          if (!state->title)
-            state->lasterr = gpg_error_from_syserror ();
-          else
-            state->idx = s_init;
-        }
+        state->idx = s_init;
     }
   else
     state->idx = s_b64_0;
@@ -123,6 +106,7 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
 
   for (s=d=buffer; length && !state->stop_seen; length--, s++)
     {
+    again:
       switch (ds)
         {
         case s_idle:
@@ -136,12 +120,42 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
           ds = s_lfseen;
         case s_lfseen:
           if (*s != "-----BEGIN "[pos])
-            ds = s_idle;
+            {
+              ds = s_idle;
+              goto again;
+            }
           else if (pos == 10)
-            ds = s_begin;
+            {
+              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;
@@ -229,10 +243,11 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
 gpg_error_t
 b64dec_finish (struct b64state *state)
 {
+  xfree (state->title);
+  state->title = NULL;
+
   if (state->lasterr)
     return state->lasterr;
 
-  xfree (state->title);
-  state->title = NULL;
   return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
 }
index 9101d98..af861fc 100644 (file)
@@ -1,30 +1,22 @@
 /* b64enc.c - Simple Base64 encoder.
  * Copyright (C) 2001, 2003, 2004, 2008, 2010,
  *               2011 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2004, 2008, 2010,
+ *               2011 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 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.
+ * 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 General Public License
+ * 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/>.
  */
 
index 490dbf5..d3c2833 100644 (file)
@@ -114,6 +114,7 @@ ccparray_put (ccparray_t *cpa, const char *value)
         }
       for (n=0; n < cpa->size; n++)
         newarray[n] = cpa->array[n];
+      xfree (cpa->array);
       cpa->array = newarray;
       cpa->size = newsize;
 
index aefb653..b1b56f3 100644 (file)
@@ -523,6 +523,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
     {
       /* This is the child. */
       gcry_control (GCRYCTL_TERM_SECMEM);
+      es_fclose (infp);
       es_fclose (outfp);
       es_fclose (errfp);
       do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1],
index 897450e..b43e7cb 100644 (file)
@@ -224,7 +224,7 @@ static gpg_error_t
 copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
 {
   gpg_error_t err;
-  size_t nwritten;
+  size_t nwritten = 0;
 
   if (c->nread == 0)
     {
@@ -390,7 +390,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
   /* Now read as long as we have something to poll.  We continue
      reading even after EOF or error on stdout so that we get the
      other error messages or remaining outut.  */
-  while (!fds[1].ignore && !fds[2].ignore)
+  while (! (fds[1].ignore && fds[2].ignore))
     {
       count = es_poll (fds, DIM(fds), -1);
       if (count == -1)
@@ -465,20 +465,25 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
                          pgmname, gpg_strerror (err));
               goto leave;
             }
+
+          if (es_feof (fds[1].stream))
+            {
+              err = copy_buffer_flush (&cpbuf_out, output);
+              if (err)
+                {
+                  log_error ("error reading data from '%s': %s\n",
+                             pgmname, gpg_strerror (err));
+                  goto leave;
+                }
+
+              fds[1].ignore = 1; /* ready.  */
+            }
         }
 
       if (fds[2].got_read)
         read_and_log_stderr (&fderrstate, fds + 2);
     }
 
-  err = copy_buffer_flush (&cpbuf_out, output);
-  if (err)
-    {
-      log_error ("error reading data from '%s': %s\n",
-                 pgmname, gpg_strerror (err));
-      goto leave;
-    }
-
   read_and_log_stderr (&fderrstate, NULL); /* Flush.  */
   es_fclose (infp); infp = NULL;
   es_fclose (extrafp); extrafp = NULL;
index 115f725..dd9c196 100644 (file)
@@ -723,6 +723,39 @@ asctimestamp (u32 stamp)
 }
 
 
+/* Return the timestamp STAMP in RFC-2822 format.  This is always done
+ * in the C locale.  We return the gmtime to avoid computing the
+ * timezone. The caller must release the returned string.
+ *
+ * Example: "Mon, 27 Jun 2016 1:42:00 +0000".
+ */
+char *
+rfctimestamp (u32 stamp)
+{
+  time_t atime = stamp;
+  struct tm tmbuf, *tp;
+
+
+  if (IS_INVALID_TIME_T (atime))
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  tp = gnupg_gmtime (&atime, &tmbuf);
+  if (!tp)
+    return NULL;
+  return xtryasprintf ("%.3s, %02d %.3s %04d %02d:%02d:%02d +0000",
+                       ("SunMonTueWedThuFriSat" + (tp->tm_wday%7)*3),
+                       tp->tm_mday,
+                       ("JanFebMarAprMayJunJulAugSepOctNovDec"
+                        + (tp->tm_mon%12)*3),
+                       tp->tm_year + 1900,
+                       tp->tm_hour,
+                       tp->tm_min,
+                       tp->tm_sec);
+}
+
 
 static int
 days_per_year (int y)
index cbc257a..08cb3b1 100644 (file)
@@ -59,6 +59,7 @@ const char *strtimevalue (u32 stamp);
 const char *strtimestamp (u32 stamp); /* GMT */
 const char *isotimestamp (u32 stamp); /* GMT */
 const char *asctimestamp (u32 stamp); /* localized */
+char *rfctimestamp (u32 stamp);       /* RFC format, malloced. */
 gpg_error_t add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds);
 gpg_error_t add_days_to_isotime (gnupg_isotime_t atime, int ndays);
 gpg_error_t check_isotime (const gnupg_isotime_t atime);
index c68a4e6..c406ffe 100644 (file)
@@ -106,6 +106,10 @@ register_mem_cleanup_func (void (*func)(void))
 {
   mem_cleanup_item_t item;
 
+  for (item = mem_cleanup_list; item; item = item->next)
+    if (item->func == func)
+      return; /* Function has already been registered.  */
+
   item = malloc (sizeof *item);
   if (item)
     {
index c8ec00f..f3d67b4 100644 (file)
@@ -2530,9 +2530,6 @@ iobuf_get_fname_nonnull (iobuf_t a)
 void
 iobuf_set_partial_body_length_mode (iobuf_t a, size_t len)
 {
-  block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
-
-  ctx->use = a->use;
   if (!len)
     /* Disable partial body length mode.  */
     {
@@ -2546,6 +2543,8 @@ iobuf_set_partial_body_length_mode (iobuf_t a, size_t len)
   else
     /* Enabled partial body length mode.  */
     {
+      block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
+      ctx->use = a->use;
       ctx->partial = 1;
       ctx->size = 0;
       ctx->first_c = len;
similarity index 79%
rename from common/private-keys.c
rename to common/name-value.c
index 4cf7d22..0b32a44 100644 (file)
@@ -1,4 +1,4 @@
-/* private-keys.c - Parser and writer for the extended private key format.
+/* name-value.c - Parser and writer for a name-value format.
  *     Copyright (C) 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+/*
+ * This module aso provides features for the extended private key
+ * format of gpg-agent.
+ */
+
 #include <config.h>
 #include <assert.h>
 #include <gcrypt.h>
 #include <gpg-error.h>
 #include <string.h>
 
-#include "private-keys.h"
 #include "mischelp.h"
 #include "strlist.h"
 #include "util.h"
+#include "name-value.h"
 
-struct private_key_container
+struct name_value_container
 {
-  struct private_key_entry *first;
-  struct private_key_entry *last;
+  struct name_value_entry *first;
+  struct name_value_entry *last;
+  unsigned int private_key_mode:1;
 };
 
 
-struct private_key_entry
+struct name_value_entry
 {
-  struct private_key_entry *prev;
-  struct private_key_entry *next;
+  struct name_value_entry *prev;
+  struct name_value_entry *next;
 
   /* The name.  Comments and blank lines have NAME set to NULL.  */
   char *name;
@@ -70,38 +76,59 @@ my_error_from_syserror (void)
 }
 
 
+static inline gpg_error_t
+my_error (gpg_err_code_t ec)
+{
+  return gpg_err_make (default_errsource, ec);
+}
+
+
 \f
 
 /* Allocation and deallocation.  */
 
 /* Allocate a private key container structure.  */
-pkc_t
-pkc_new (void)
+nvc_t
+nvc_new (void)
+{
+  return xtrycalloc (1, sizeof (struct name_value_container));
+}
+
+
+/* Allocate a private key container structure for use with private keys.  */
+nvc_t
+nvc_new_private_key (void)
 {
-  return xtrycalloc (1, sizeof (struct private_key_container));
+  nvc_t nvc = nvc_new ();
+  if (nvc)
+    nvc->private_key_mode = 1;
+  return nvc;
 }
 
 
 static void
-pke_release (pke_t entry)
+nve_release (nve_t entry, int private_key_mode)
 {
   if (entry == NULL)
     return;
 
   xfree (entry->name);
-  if (entry->value)
+  if (entry->value && private_key_mode)
     wipememory (entry->value, strlen (entry->value));
   xfree (entry->value);
-  free_strlist_wipe (entry->raw_value);
+  if (private_key_mode)
+    free_strlist_wipe (entry->raw_value);
+  else
+    free_strlist (entry->raw_value);
   xfree (entry);
 }
 
 
 /* Release a private key container structure.  */
 void
-pkc_release (pkc_t pk)
+nvc_release (nvc_t pk)
 {
-  pke_t e, next;
+  nve_t e, next;
 
   if (pk == NULL)
     return;
@@ -109,7 +136,7 @@ pkc_release (pkc_t pk)
   for (e = pk->first; e; e = next)
     {
       next = e->next;
-      pke_release (e);
+      nve_release (e, pk->private_key_mode);
     }
 
   xfree (pk);
@@ -140,7 +167,7 @@ valid_name (const char *name)
 
 /* Makes sure that ENTRY has a RAW_VALUE.  */
 static gpg_error_t
-assert_raw_value (pke_t entry)
+assert_raw_value (nve_t entry)
 {
   gpg_error_t err = 0;
   size_t len, offset;
@@ -256,7 +283,7 @@ continuation_length (const char *s, int *swallow_ws, const char **start)
 
 /* Makes sure that ENTRY has a VALUE.  */
 static gpg_error_t
-assert_value (pke_t entry)
+assert_value (nve_t entry)
 {
   size_t len;
   int swallow_ws;
@@ -297,7 +324,7 @@ assert_value (pke_t entry)
 
 /* Get the name.  */
 char *
-pke_name (pke_t pke)
+nve_name (nve_t pke)
 {
   return pke->name;
 }
@@ -305,7 +332,7 @@ pke_name (pke_t pke)
 
 /* Get the value.  */
 char *
-pke_value (pke_t pke)
+nve_value (nve_t pke)
 {
   if (assert_value (pke))
     return NULL;
@@ -321,23 +348,26 @@ pke_value (pke_t pke)
    given.  If PRESERVE_ORDER is not given, entries with the same name
    are grouped.  NAME, VALUE and RAW_VALUE is consumed.  */
 static gpg_error_t
-_pkc_add (pkc_t pk, char *name, char *value, strlist_t raw_value,
+_nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
          int preserve_order)
 {
   gpg_error_t err = 0;
-  pke_t e;
+  nve_t e;
 
   assert (value || raw_value);
 
   if (name && ! valid_name (name))
     {
-      err = gpg_error (GPG_ERR_INV_NAME);
+      err = my_error (GPG_ERR_INV_NAME);
       goto leave;
     }
 
-  if (name && ascii_strcasecmp (name, "Key:") == 0 && pkc_lookup (pk, "Key:"))
+  if (name
+      && pk->private_key_mode
+      && !ascii_strcasecmp (name, "Key:")
+      && nvc_lookup (pk, "Key:"))
     {
-      err = gpg_error (GPG_ERR_INV_NAME);
+      err = my_error (GPG_ERR_INV_NAME);
       goto leave;
     }
 
@@ -354,21 +384,21 @@ _pkc_add (pkc_t pk, char *name, char *value, strlist_t raw_value,
 
   if (pk->first)
     {
-      pke_t last;
+      nve_t last;
 
       if (preserve_order || name == NULL)
        last = pk->last;
       else
        {
          /* See if there is already an entry with NAME.  */
-         last = pkc_lookup (pk, name);
+         last = nvc_lookup (pk, name);
 
          /* If so, find the last in that block.  */
          if (last)
             {
               while (last->next)
                 {
-                  pke_t next = last->next;
+                  nve_t next = last->next;
 
                   if (next->name && ascii_strcasecmp (next->name, name) == 0)
                     last = next;
@@ -414,7 +444,7 @@ _pkc_add (pkc_t pk, char *name, char *value, strlist_t raw_value,
 /* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
    is not updated but the new entry is appended.  */
 gpg_error_t
-pkc_add (pkc_t pk, const char *name, const char *value)
+nvc_add (nvc_t pk, const char *name, const char *value)
 {
   char *k, *v;
 
@@ -429,7 +459,7 @@ pkc_add (pkc_t pk, const char *name, const char *value)
       return my_error_from_syserror ();
     }
 
-  return _pkc_add (pk, k, v, NULL, 0);
+  return _nvc_add (pk, k, v, NULL, 0);
 }
 
 
@@ -437,14 +467,14 @@ pkc_add (pkc_t pk, const char *name, const char *value)
    is updated with VALUE.  If multiple entries with NAME exist, the
    first entry is updated.  */
 gpg_error_t
-pkc_set (pkc_t pk, const char *name, const char *value)
+nvc_set (nvc_t pk, const char *name, const char *value)
 {
-  pke_t e;
+  nve_t e;
 
   if (! valid_name (name))
     return GPG_ERR_INV_NAME;
 
-  e = pkc_lookup (pk, name);
+  e = nvc_lookup (pk, name);
   if (e)
     {
       char *v;
@@ -463,13 +493,13 @@ pkc_set (pkc_t pk, const char *name, const char *value)
       return 0;
     }
   else
-    return pkc_add (pk, name, value);
+    return nvc_add (pk, name, value);
 }
 
 
 /* Delete the given entry from PK.  */
 void
-pkc_delete (pkc_t pk, pke_t entry)
+nvc_delete (nvc_t pk, nve_t entry)
 {
   if (entry->prev)
     entry->prev->next = entry->next;
@@ -481,7 +511,7 @@ pkc_delete (pkc_t pk, pke_t entry)
   else
     pk->last = entry->prev;
 
-  pke_release (entry);
+  nve_release (entry, pk->private_key_mode);
 }
 
 \f
@@ -489,10 +519,10 @@ pkc_delete (pkc_t pk, pke_t entry)
 /* Lookup and iteration.  */
 
 /* Get the first non-comment entry.  */
-pke_t
-pkc_first (pkc_t pk)
+nve_t
+nvc_first (nvc_t pk)
 {
-  pke_t entry;
+  nve_t entry;
   for (entry = pk->first; entry; entry = entry->next)
     if (entry->name)
       return entry;
@@ -501,10 +531,10 @@ pkc_first (pkc_t pk)
 
 
 /* Get the first entry with the given name.  */
-pke_t
-pkc_lookup (pkc_t pk, const char *name)
+nve_t
+nvc_lookup (nvc_t pk, const char *name)
 {
-  pke_t entry;
+  nve_t entry;
   for (entry = pk->first; entry; entry = entry->next)
     if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
       return entry;
@@ -513,8 +543,8 @@ pkc_lookup (pkc_t pk, const char *name)
 
 
 /* Get the next non-comment entry.  */
-pke_t
-pke_next (pke_t entry)
+nve_t
+nve_next (nve_t entry)
 {
   for (entry = entry->next; entry; entry = entry->next)
     if (entry->name)
@@ -524,8 +554,8 @@ pke_next (pke_t entry)
 
 
 /* Get the next entry with the given name.  */
-pke_t
-pke_next_value (pke_t entry, const char *name)
+nve_t
+nve_next_value (nve_t entry, const char *name)
 {
   for (entry = entry->next; entry; entry = entry->next)
     if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
@@ -539,14 +569,14 @@ pke_next_value (pke_t entry, const char *name)
 
 /* Get the private key.  */
 gpg_error_t
-pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp)
+nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp)
 {
   gpg_error_t err;
-  pke_t e;
+  nve_t e;
 
-  e = pkc_lookup (pk, "Key:");
+  e = pk->private_key_mode? nvc_lookup (pk, "Key:") : NULL;
   if (e == NULL)
-    return gpg_error (GPG_ERR_MISSING_KEY);
+    return my_error (GPG_ERR_MISSING_KEY);
 
   err = assert_value (e);
   if (err)
@@ -558,12 +588,15 @@ pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp)
 
 /* Set the private key.  */
 gpg_error_t
-pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp)
+nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp)
 {
   gpg_error_t err;
   char *raw, *clean, *p;
   size_t len, i;
 
+  if (!pk->private_key_mode)
+    return my_error (GPG_ERR_MISSING_KEY);
+
   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
 
   raw = xtrymalloc (len);
@@ -605,7 +638,7 @@ pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp)
     }
   *p = 0;
 
-  err = pkc_set (pk, "Key:", clean);
+  err = nvc_set (pk, "Key:", clean);
   xfree (raw);
   xfree (clean);
   return err;
@@ -615,11 +648,9 @@ pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp)
 
 /* Parsing and serialization.  */
 
-/* Parse STREAM and return a newly allocated private key container
-   structure in RESULT.  If ERRLINEP is given, the line number the
-   parser was last considering is stored there.  */
-gpg_error_t
-pkc_parse (pkc_t *result, int *errlinep, estream_t stream)
+static gpg_error_t
+do_nvc_parse (nvc_t *result, int *errlinep, estream_t stream,
+              int for_private_key)
 {
   gpg_error_t err = 0;
   gpgrt_ssize_t len;
@@ -628,8 +659,7 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream)
   char *name = NULL;
   strlist_t raw_value = NULL;
 
-
-  *result = pkc_new ();
+  *result = for_private_key? nvc_new_private_key () : nvc_new ();
   if (*result == NULL)
     return my_error_from_syserror ();
 
@@ -659,7 +689,7 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream)
       /* No continuation.  Add the current entry if any.  */
       if (raw_value)
        {
-         err = _pkc_add (*result, name, NULL, raw_value, 1);
+         err = _nvc_add (*result, name, NULL, raw_value, 1);
          if (err)
            goto leave;
        }
@@ -675,7 +705,7 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream)
          colon = strchr (buf, ':');
          if (colon == NULL)
            {
-             err = gpg_error (GPG_ERR_INV_VALUE);
+             err = my_error (GPG_ERR_INV_VALUE);
              goto leave;
            }
 
@@ -708,13 +738,13 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream)
 
   /* Add the final entry.  */
   if (raw_value)
-    err = _pkc_add (*result, name, NULL, raw_value, 1);
+    err = _nvc_add (*result, name, NULL, raw_value, 1);
 
  leave:
   gpgrt_free (buf);
   if (err)
     {
-      pkc_release (*result);
+      nvc_release (*result);
       *result = NULL;
     }
 
@@ -722,12 +752,33 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream)
 }
 
 
+/* Parse STREAM and return a newly allocated name value container
+   structure in RESULT.  If ERRLINEP is given, the line number the
+   parser was last considering is stored there.  */
+gpg_error_t
+nvc_parse (nvc_t *result, int *errlinep, estream_t stream)
+{
+  return do_nvc_parse (result, errlinep, stream, 0);
+}
+
+
+/* Parse STREAM and return a newly allocated name value container
+   structure in RESULT - assuming the extended private key format.  If
+   ERRLINEP is given, the line number the parser was last considering
+   is stored there.  */
+gpg_error_t
+nvc_parse_private_key (nvc_t *result, int *errlinep, estream_t stream)
+{
+  return do_nvc_parse (result, errlinep, stream, 1);
+}
+
+
 /* Write a representation of PK to STREAM.  */
 gpg_error_t
-pkc_write (pkc_t pk, estream_t stream)
+nvc_write (nvc_t pk, estream_t stream)
 {
   gpg_error_t err;
-  pke_t entry;
+  nve_t entry;
   strlist_t s;
 
   for (entry = pk->first; entry; entry = entry->next)
similarity index 56%
rename from common/private-keys.h
rename to common/name-value.h
index d21e94f..f5f17e6 100644 (file)
@@ -1,4 +1,4 @@
-/* private-keys.h - Parser and writer for the extended private key format.
+/* name-value.h - Parser and writer for a name-value format.
  *     Copyright (C) 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef GNUPG_COMMON_PRIVATE_KEYS_H
-#define GNUPG_COMMON_PRIVATE_KEYS_H
+#ifndef GNUPG_COMMON_NAME_VALUE_H
+#define GNUPG_COMMON_NAME_VALUE_H
 
-struct private_key_container;
-typedef struct private_key_container *pkc_t;
+struct name_value_container;
+typedef struct name_value_container *nvc_t;
 
-struct private_key_entry;
-typedef struct private_key_entry *pke_t;
+struct name_value_entry;
+typedef struct name_value_entry *nve_t;
 
 \f
 
 /* Memory management, and dealing with entries.  */
 
-/* Allocate a private key container structure.  */
-pkc_t pkc_new (void);
+/* Allocate a name value container structure.  */
+nvc_t nvc_new (void);
 
-/* Release a private key container structure.  */
-void pkc_release (pkc_t pk);
+/* Allocate a name value container structure for use with the extended
+ * private key format.  */
+nvc_t nvc_new_private_key (void);
+
+/* Release a name value container structure.  */
+void nvc_release (nvc_t pk);
 
 /* Get the name.  */
-char *pke_name (pke_t pke);
+char *nve_name (nve_t pke);
 
 /* Get the value.  */
-char *pke_value (pke_t pke);
+char *nve_value (nve_t pke);
 
 \f
 
 /* Lookup and iteration.  */
 
 /* Get the first non-comment entry.  */
-pke_t pkc_first (pkc_t pk);
+nve_t nvc_first (nvc_t pk);
 
 /* Get the first entry with the given name.  */
-pke_t pkc_lookup (pkc_t pk, const char *name);
+nve_t nvc_lookup (nvc_t pk, const char *name);
 
 /* Get the next non-comment entry.  */
-pke_t pke_next (pke_t entry);
+nve_t nve_next (nve_t entry);
 
 /* Get the next entry with the given name.  */
-pke_t pke_next_value (pke_t entry, const char *name);
+nve_t nve_next_value (nve_t entry, const char *name);
 
 \f
 
@@ -74,25 +78,25 @@ pke_t pke_next_value (pke_t entry, const char *name);
 
 /* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
    is not updated but the new entry is appended.  */
-gpg_error_t pkc_add (pkc_t pk, const char *name, const char *value);
+gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value);
 
 /* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
    is updated with VALUE.  If multiple entries with NAME exist, the
    first entry is updated.  */
-gpg_error_t pkc_set (pkc_t pk, const char *name, const char *value);
+gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
 
 /* Delete the given entry from PK.  */
-void pkc_delete (pkc_t pk, pke_t pke);
+void nvc_delete (nvc_t pk, nve_t pke);
 
 \f
 
 /* Private key handling.  */
 
 /* Get the private key.  */
-gpg_error_t pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp);
+gpg_error_t nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp);
 
 /* Set the private key.  */
-gpg_error_t pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp);
+gpg_error_t nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp);
 
 \f
 
@@ -101,9 +105,16 @@ gpg_error_t pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp);
 /* Parse STREAM and return a newly allocated private key container
    structure in RESULT.  If ERRLINEP is given, the line number the
    parser was last considering is stored there.  */
-gpg_error_t pkc_parse (pkc_t *result, int *errlinep, estream_t stream);
+gpg_error_t nvc_parse (nvc_t *result, int *errlinep, estream_t stream);
+
+/* Parse STREAM and return a newly allocated name value container
+   structure in RESULT - assuming the extended private key format.  If
+   ERRLINEP is given, the line number the parser was last considering
+   is stored there.  */
+gpg_error_t nvc_parse_private_key (nvc_t *result, int *errlinep,
+                                   estream_t stream);
 
 /* Write a representation of PK to STREAM.  */
-gpg_error_t pkc_write (pkc_t pk, estream_t stream);
+gpg_error_t nvc_write (nvc_t pk, estream_t stream);
 
-#endif /* GNUPG_COMMON_PRIVATE_KEYS_H */
+#endif /* GNUPG_COMMON_NAME_VALUE_H */
index f8b86e1..2c0ace2 100644 (file)
@@ -115,6 +115,7 @@ typedef enum
     SIGSUBPKT_FEATURES      = 30, /* Feature flags. */
 
     SIGSUBPKT_SIGNATURE     = 32, /* Embedded signature. */
+    SIGSUBPKT_ISSUER_FPR    = 33, /* EXPERIMENTAL: Issuer fingerprint. */
 
     SIGSUBPKT_FLAG_CRITICAL = 128
   }
diff --git a/common/recsel.c b/common/recsel.c
new file mode 100644 (file)
index 0000000..5dc685f
--- /dev/null
@@ -0,0 +1,571 @@
+/* recsel.c - Record selection
+ * Copyright (C) 2014, 2016 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 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.
+ *
+ * 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 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 <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "recsel.h"
+
+/* Select operators.  */
+typedef enum
+  {
+    SELECT_SAME,
+    SELECT_SUB,
+    SELECT_NONEMPTY,
+    SELECT_ISTRUE,
+    SELECT_EQ, /* Numerically equal.  */
+    SELECT_LE,
+    SELECT_GE,
+    SELECT_LT,
+    SELECT_GT
+  } select_op_t;
+
+
+/* Definition for a select expression.  */
+struct recsel_expr_s
+{
+  recsel_expr_t next;
+  select_op_t op;       /* Operation code.  */
+  unsigned int not:1;   /* Negate operators. */
+  unsigned int disjun:1;/* Start of a disjunction.  */
+  unsigned int xcase:1; /* String match is case sensitive.  */
+  const char *value;    /* (Points into NAME.)  */
+  long numvalue;        /* strtol of VALUE.  */
+  char name[1];         /* Name of the property.  */
+};
+
+
+/* Helper */
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+  return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+/* Helper */
+static inline gpg_error_t
+my_error (gpg_err_code_t ec)
+{
+  return gpg_err_make (default_errsource, ec);
+}
+
+
+/* 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.
+ *
+ * FIXME: Move this to a stringhelp.c
+ */
+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;
+}
+
+
+/* Return a pointer to the next logical connection operator or NULL if
+ * none.  */
+static char *
+find_next_lc (char *string)
+{
+  char *p1, *p2;
+
+  p1 = strchr (string, '&');
+  if (p1 && p1[1] != '&')
+    p1 = NULL;
+  p2 = strchr (string, '|');
+  if (p2 && p2[1] != '|')
+    p2 = NULL;
+  if (p1 && !p2)
+    return p1;
+  if (!p1)
+    return p2;
+  return p1 < p2 ? p1 : p2;
+}
+
+
+/* Parse an expression.  The expression syntax is:
+ *
+ *   [<lc>] {{<flag>} PROPNAME <op> VALUE [<lc>]}
+ *
+ * A [] indicates an optional part, a {} a repetition.  PROPNAME and
+ * VALUE may not be the empty string.  White space between the
+ * elements is ignored.  Numerical values are computed as long int;
+ * standard C notation applies.  <lc> is the logical connection
+ * operator; either "&&" for a conjunction or "||" for a disjunction.
+ * A conjunction is assumed at the begin of an expression and
+ * conjunctions have higher precedence than disjunctions.  If VALUE
+ * starts with one of the characters used in any <op> a space after
+ * the <op> is required.  A VALUE is terminated by an <lc> unless the
+ * "--" <flag> is used in which case the VALUE spans to the end of the
+ * expression.  <op> may be any of
+ *
+ *   =~  Substring must match
+ *   !~  Substring must not match
+ *   =   The full string must match
+ *   <>  The full string must not match
+ *   ==  The numerical value must match
+ *   !=  The numerical value must not match
+ *   <=  The numerical value of the field must be LE than the value.
+ *   <   The numerical value of the field must be LT than the value.
+ *   >=  The numerical value of the field must be GT than the value.
+ *   >=  The numerical value of the field must be GE than the value.
+ *   -n  True if value is not empty (no VALUE parameter allowed).
+ *   -z  True if value is empty (no VALUE parameter allowed).
+ *   -t  Alias for "PROPNAME != 0" (no VALUE parameter allowed).
+ *   -f  Alias for "PROPNAME == 0" (no VALUE parameter allowed).
+ *
+ * Values for <flag> must be space separated and any of:
+ *
+ *   --  VALUE spans to the end of the expression.
+ *   -c  The string match in this part is done case-sensitive.
+ *
+ * For example four calls to recsel_parse_expr() with these values for
+ * EXPR
+ *
+ *  "uid =~ Alfa"
+ *  "&& uid !~ Test"
+ *  "|| uid =~ Alpha"
+ *  "uid !~ Test"
+ *
+ * or the equivalent expression
+ *
+ *  "uid =~ Alfa" && uid !~ Test" || uid =~ Alpha" && "uid !~ Test"
+ *
+ * are making a selector for records where the "uid" property contains
+ * the strings "Alfa" or "Alpha" but not the String "test".
+ *
+ * The caller must pass the address of a selector variable to this
+ * function and initialize the value of the function to NULL before
+ * the first call.  recset_release needs to be called to free the
+ * selector.
+ */
+gpg_error_t
+recsel_parse_expr (recsel_expr_t *selector, const char *expression)
+{
+  recsel_expr_t se_head = NULL;
+  recsel_expr_t se, se2;
+  char *expr_buffer;
+  char *expr;
+  char *s0, *s;
+  int toend = 0;
+  int xcase = 0;
+  int disjun = 0;
+  char *next_lc = NULL;
+
+  while (*expression == ' ' || *expression == '\t')
+    expression++;
+
+  expr_buffer = xtrystrdup (expression);
+  if (!expr_buffer)
+    return my_error_from_syserror ();
+  expr = expr_buffer;
+
+  if (*expr == '|' && expr[1] == '|')
+    {
+      disjun = 1;
+      expr += 2;
+    }
+  else if (*expr == '&' && expr[1] == '&')
+    expr += 2;
+
+ next_term:
+  while (*expr == ' ' || *expr == '\t')
+    expr++;
+
+  while (*expr == '-')
+    {
+      switch (*++expr)
+        {
+        case '-': toend = 1; break;
+        case 'c': xcase = 1; break;
+        default:
+          log_error ("invalid flag '-%c' in expression\n", *expr);
+          recsel_release (se_head);
+          xfree (expr_buffer);
+          return my_error (GPG_ERR_INV_FLAG);
+        }
+      expr++;
+      while (*expr == ' ' || *expr == '\t')
+        expr++;
+    }
+
+  next_lc = toend? NULL : find_next_lc (expr);
+  if (next_lc)
+    *next_lc = 0;  /* Terminate this term.  */
+
+  se = xtrymalloc (sizeof *se + strlen (expr));
+  if (!se)
+    return my_error_from_syserror ();
+  strcpy (se->name, expr);
+  se->next = NULL;
+  se->not = 0;
+  se->disjun = disjun;
+  se->xcase = xcase;
+
+  if (!se_head)
+    se_head = se;
+  else
+    {
+      for (se2 = se_head; se2->next; se2 = se2->next)
+        ;
+      se2->next = se;
+    }
+
+
+  s = strpbrk (expr, "=<>!~-");
+  if (!s || s == expr )
+    {
+      log_error ("no field name given in expression\n");
+      recsel_release (se_head);
+      xfree (expr_buffer);
+      return my_error (GPG_ERR_NO_NAME);
+    }
+  s0 = s;
+
+  if (!strncmp (s, "=~", 2))
+    {
+      se->op = SELECT_SUB;
+      s += 2;
+    }
+  else if (!strncmp (s, "!~", 2))
+    {
+      se->op = SELECT_SUB;
+      se->not = 1;
+      s += 2;
+    }
+  else if (!strncmp (s, "<>", 2))
+    {
+      se->op = SELECT_SAME;
+      se->not = 1;
+      s += 2;
+    }
+  else if (!strncmp (s, "==", 2))
+    {
+      se->op = SELECT_EQ;
+      s += 2;
+    }
+  else if (!strncmp (s, "!=", 2))
+    {
+      se->op = SELECT_EQ;
+      se->not = 1;
+      s += 2;
+    }
+  else if (!strncmp (s, "<=", 2))
+    {
+      se->op = SELECT_LE;
+      s += 2;
+    }
+  else if (!strncmp (s, ">=", 2))
+    {
+      se->op = SELECT_GE;
+      s += 2;
+    }
+  else if (!strncmp (s, "<", 1))
+    {
+      se->op = SELECT_LT;
+      s += 1;
+    }
+  else if (!strncmp (s, ">", 1))
+    {
+      se->op = SELECT_GT;
+      s += 1;
+    }
+  else if (!strncmp (s, "=", 1))
+    {
+      se->op = SELECT_SAME;
+      s += 1;
+    }
+  else if (!strncmp (s, "-z", 2))
+    {
+      se->op = SELECT_NONEMPTY;
+      se->not = 1;
+      s += 2;
+    }
+  else if (!strncmp (s, "-n", 2))
+    {
+      se->op = SELECT_NONEMPTY;
+      s += 2;
+    }
+  else if (!strncmp (s, "-f", 2))
+    {
+      se->op = SELECT_ISTRUE;
+      se->not = 1;
+      s += 2;
+    }
+  else if (!strncmp (s, "-t", 2))
+    {
+      se->op = SELECT_ISTRUE;
+      s += 2;
+    }
+  else
+    {
+      log_error ("invalid operator in expression\n");
+      recsel_release (se_head);
+      xfree (expr_buffer);
+      return my_error (GPG_ERR_INV_OP);
+    }
+
+  /* We require that a space is used if the value starts with any of
+     the operator characters.  */
+  if (se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE)
+    ;
+  else if (strchr ("=<>!~", *s))
+    {
+      log_error ("invalid operator in expression\n");
+      recsel_release (se_head);
+      xfree (expr_buffer);
+      return my_error (GPG_ERR_INV_OP);
+    }
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE)
+    {
+      if (*s)
+        {
+          log_error ("value given for -n or -z\n");
+          recsel_release (se_head);
+          xfree (expr_buffer);
+          return my_error (GPG_ERR_SYNTAX);
+        }
+    }
+  else
+    {
+      if (!*s)
+        {
+          log_error ("no value given in expression\n");
+          recsel_release (se_head);
+          xfree (expr_buffer);
+          return my_error (GPG_ERR_MISSING_VALUE);
+        }
+    }
+
+  se->name[s0 - expr] = 0;
+  trim_spaces (se->name);
+  if (!se->name[0])
+    {
+      log_error ("no field name given in expression\n");
+      recsel_release (se_head);
+      xfree (expr_buffer);
+      return my_error (GPG_ERR_NO_NAME);
+    }
+
+  trim_spaces (se->name + (s - expr));
+  se->value = se->name + (s - expr);
+  if (!se->value[0] && !(se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE))
+    {
+      log_error ("no value given in expression\n");
+      recsel_release (se_head);
+      xfree (expr_buffer);
+      return my_error (GPG_ERR_MISSING_VALUE);
+    }
+
+  se->numvalue = strtol (se->value, NULL, 0);
+
+  if (next_lc)
+    {
+      disjun = next_lc[1] == '|';
+      expr = next_lc + 2;
+      goto next_term;
+    }
+
+  /* Read:y Append to passes last selector.  */
+  if (!*selector)
+    *selector = se_head;
+  else
+    {
+      for (se2 = *selector; se2->next; se2 = se2->next)
+        ;
+      se2->next = se_head;
+    }
+
+  xfree (expr_buffer);
+  return 0;
+}
+
+
+void
+recsel_release (recsel_expr_t a)
+{
+  while (a)
+    {
+      recsel_expr_t tmp = a->next;
+      xfree (a);
+      a = tmp;
+    }
+}
+
+
+void
+recsel_dump (recsel_expr_t selector)
+{
+  recsel_expr_t se;
+
+  log_debug ("--- Begin selectors ---\n");
+  for (se = selector; se; se = se->next)
+    {
+      log_debug ("%s %s %s %s '%s'\n",
+                 se==selector? "  ": (se->disjun? "||":"&&"),
+                 se->xcase?  "-c":"  ",
+                 se->name,
+                 se->op == SELECT_SAME?    (se->not? "<>":"= "):
+                 se->op == SELECT_SUB?     (se->not? "!~":"=~"):
+                 se->op == SELECT_NONEMPTY?(se->not? "-z":"-n"):
+                 se->op == SELECT_ISTRUE?  (se->not? "-f":"-t"):
+                 se->op == SELECT_EQ?      (se->not? "!=":"=="):
+                 se->op == SELECT_LT?      "< ":
+                 se->op == SELECT_LE?      "<=":
+                 se->op == SELECT_GT?      "> ":
+                 se->op == SELECT_GE?      ">=":"[oops]",
+                 se->value);
+    }
+  log_debug ("--- End selectors ---\n");
+}
+
+
+/* Return true if the record RECORD has been selected.  The GETVAL
+ * function is called with COOKIE and the NAME of a property used in
+ * the expression.  */
+int
+recsel_select (recsel_expr_t selector,
+               const char *(*getval)(void *cookie, const char *propname),
+               void *cookie)
+{
+  recsel_expr_t se;
+  const char *value;
+  size_t selen, valuelen;
+  long numvalue;
+  int result = 1;
+
+  se = selector;
+  while (se)
+    {
+      value = getval? getval (cookie, se->name) : NULL;
+      if (!value)
+        value = "";
+
+      if (!*value)
+        {
+          /* Field is empty.  */
+          result = 0;
+        }
+      else /* Field has a value.  */
+        {
+          valuelen = strlen (value);
+          numvalue = strtol (value, NULL, 0);
+          selen = strlen (se->value);
+
+          switch (se->op)
+            {
+            case SELECT_SAME:
+              if (se->xcase)
+                result = (valuelen==selen && !memcmp (value,se->value,selen));
+              else
+                result = (valuelen==selen && !memicmp (value,se->value,selen));
+              break;
+            case SELECT_SUB:
+              if (se->xcase)
+                result = !!my_memstr (value, valuelen, se->value);
+              else
+                result = !!memistr (value, valuelen, se->value);
+              break;
+            case SELECT_NONEMPTY:
+              result = !!valuelen;
+              break;
+            case SELECT_ISTRUE:
+              result = !!numvalue;
+              break;
+            case SELECT_EQ:
+              result = (numvalue == se->numvalue);
+              break;
+            case SELECT_GT:
+              result = (numvalue > se->numvalue);
+              break;
+            case SELECT_GE:
+              result = (numvalue >= se->numvalue);
+              break;
+            case SELECT_LT:
+              result = (numvalue < se->numvalue);
+              break;
+            case SELECT_LE:
+              result = (numvalue <= se->numvalue);
+              break;
+            }
+        }
+
+      if (se->not)
+        result = !result;
+
+      if (result)
+        {
+          /* This expression evaluated to true.  See wether there are
+             remaining expressions in this conjunction.  */
+          if (!se->next || se->next->disjun)
+            break; /* All expressions are true.  Return True.  */
+          se = se->next;  /* Test the next.  */
+        }
+      else
+        {
+          /* This expression evaluated to false and thus the
+           * conjuction evaluates to false.  We skip over the
+           * remaining expressions of this conjunction and continue
+           * with the next disjunction if any.  */
+          do
+            se = se->next;
+          while (se && !se->disjun);
+        }
+    }
+
+  return result;
+}
diff --git a/common/recsel.h b/common/recsel.h
new file mode 100644 (file)
index 0000000..be67afc
--- /dev/null
@@ -0,0 +1,43 @@
+/* recsel.c - Record selection
+ * Copyright (C) 2016 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 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.
+ *
+ * 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 General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef GNUPG_COMMON_RECSEL_H
+#define GNUPG_COMMON_RECSEL_H
+
+struct recsel_expr_s;
+typedef struct recsel_expr_s *recsel_expr_t;
+
+gpg_error_t recsel_parse_expr (recsel_expr_t *selector, const char *expr);
+void recsel_release (recsel_expr_t a);
+void recsel_dump (recsel_expr_t selector);
+int recsel_select (recsel_expr_t selector,
+                   const char *(*getval)(void *cookie, const char *propname),
+                   void *cookie);
+
+
+#endif /*GNUPG_COMMON_RECSEL_H*/
index bdad140..708b157 100644 (file)
@@ -340,6 +340,7 @@ agent_open (int *rfd)
   if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
        || (p-infostr)+1 >= sizeof client_addr.sun_path )
     {
+      spwq_free (infostr);
       return SPWQ_NO_AGENT;
     }
   *p++ = 0;
@@ -357,12 +358,14 @@ agent_open (int *rfd)
 #ifdef SPWQ_USE_LOGGING
       log_error ("can't create socket: %s\n", strerror(errno) );
 #endif
+      spwq_free (infostr);
       return SPWQ_SYS_ERROR;
     }
 
   memset (&client_addr, 0, sizeof client_addr);
   client_addr.sun_family = AF_UNIX;
   strcpy (client_addr.sun_path, infostr);
+  spwq_free (infostr);
   len = SUN_LEN (&client_addr);
 
 #ifdef HAVE_W32_SYSTEM
@@ -373,7 +376,8 @@ agent_open (int *rfd)
   if (rc == -1)
     {
 #ifdef SPWQ_USE_LOGGING
-      log_error ( _("can't connect to '%s': %s\n"), infostr, strerror (errno));
+      log_error (_("can't connect to '%s': %s\n"),
+                 client_addr.sun_path, strerror (errno));
 #endif
       close (fd );
       return SPWQ_IO_ERROR;
index 0e96c9e..95912e0 100644 (file)
@@ -538,6 +538,7 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
               home_buffer = xtrymalloc (n);
               if (!home_buffer)
                 {
+                  xfree (home);
                   xfree (name);
                   return NULL;
                 }
@@ -556,6 +557,7 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
           else
             strcpy (stpcpy (stpcpy (p, home), "/"), name);
 
+          xfree (home);
           xfree (name);
           name = home_buffer;
           /* Let's do a simple compression to catch the most common
index ad33dff..68824e0 100644 (file)
@@ -234,6 +234,7 @@ test_bin2hex (void)
     fail (0);
   else if (strcmp (p, hexstuff))
     fail (0);
+  xfree (p);
 
   p = bin2hex (stuff, (size_t)(-1), NULL);
   if (p)
@@ -266,6 +267,7 @@ test_bin2hexcolon (void)
     fail (0);
   else if (strcmp (p, hexstuff))
     fail (0);
+  xfree (p);
 
   p = bin2hexcolon (stuff, (size_t)(-1), NULL);
   if (p)
index 9b3139d..8a222b7 100644 (file)
@@ -54,6 +54,12 @@ test_isotime2epoch (void)
     { "20070629T160000 ",  1183132800 },
     { "20070629T160000\n", 1183132800 },
     { "20070629T160000.",  INVALID },
+#if SIZEOF_TIME_T > 4
+    { "21060207T062815", (time_t)0x0ffffffff },
+    { "21060207T062816", (time_t)0x100000000 },
+    { "21060207T062817", (time_t)0x100000001 },
+    { "21060711T120001", (time_t)4308292801  },
+#endif /*SIZEOF_TIME_T > 4*/
     { NULL, 0 }
   };
   int idx;
index 2835df4..0e6f508 100644 (file)
@@ -190,6 +190,8 @@ main (int argc, char *argv[])
        n ++;
       }
     assert (n == 10 + (strlen (content) - 10) / 2);
+
+    iobuf_close (iobuf);
   }
 
 
@@ -266,6 +268,8 @@ main (int argc, char *argv[])
     /* The string should have been truncated (max_len == 0).  */
     assert (max_len == 0);
     free (buffer);
+
+    iobuf_close (iobuf);
   }
 
   {
@@ -279,10 +283,12 @@ main (int argc, char *argv[])
     int c;
     int n;
     int lastc = 0;
+    struct content_filter_state *state;
 
     iobuf = iobuf_temp_with_content (content, strlen(content));
     rc = iobuf_push_filter (iobuf,
-                           content_filter, content_filter_new (content2));
+                           content_filter,
+                            state=content_filter_new (content2));
     assert (rc == 0);
 
     n = 0;
@@ -309,6 +315,9 @@ main (int argc, char *argv[])
            /* printf ("%d: '%c' (%d)\n", n, c, c); */
          }
       }
+
+    iobuf_close (iobuf);
+    free (state);
   }
 
   /* Write some data to a temporary filter.  Push a new filter.  The
@@ -346,6 +355,8 @@ main (int argc, char *argv[])
 
     assert (n == strlen (content) + 2 * (strlen (content2) + 1));
     assert (strcmp (buffer, "0123456789aabbcc") == 0);
+
+    iobuf_close (iobuf);
   }
 
   {
@@ -373,6 +384,8 @@ main (int argc, char *argv[])
     assert (n == 2);
     assert (buffer[0] == '3');
     assert (buffer[1] == '7');
+
+    iobuf_close (iobuf);
   }
 
   return 0;
index dfa4ada..ff48f6c 100644 (file)
@@ -87,6 +87,8 @@ run_test (void)
         fail (idx);
       else if (strcmp (mbox, testtbl[idx].mbox))
         fail (idx);
+
+      xfree (mbox);
     }
 }
 
similarity index 69%
rename from common/t-private-keys.c
rename to common/t-name-value.c
index 1027e70..3b01431 100644 (file)
@@ -1,4 +1,4 @@
-/* t-private-keys.c - Module test for private-keys.c
+/* t-name-value.c - Module test for name-value.c
  *     Copyright (C) 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
 #include <sys/stat.h>
 
 #include "util.h"
-#include "private-keys.h"
+#include "name-value.h"
 
 static int verbose;
+static int private_key_mode;
+
+
+static nvc_t
+my_nvc_new (void)
+{
+  if (private_key_mode)
+    return nvc_new_private_key ();
+  else
+    return nvc_new ();
+}
+
 
 void
-test_getting_values (pkc_t pk)
+test_getting_values (nvc_t pk)
 {
-  pke_t e;
+  nve_t e;
 
-  e = pkc_lookup (pk, "Comment:");
+  e = nvc_lookup (pk, "Comment:");
   assert (e);
 
   /* Names are case-insensitive.  */
-  e = pkc_lookup (pk, "comment:");
+  e = nvc_lookup (pk, "comment:");
   assert (e);
-  e = pkc_lookup (pk, "COMMENT:");
+  e = nvc_lookup (pk, "COMMENT:");
   assert (e);
 
-  e = pkc_lookup (pk, "SomeOtherName:");
+  e = nvc_lookup (pk, "SomeOtherName:");
   assert (e);
 }
 
 
 void
-test_key_extraction (pkc_t pk)
+test_key_extraction (nvc_t pk)
 {
   gpg_error_t err;
   gcry_sexp_t key;
 
-  err = pkc_get_private_key (pk, &key);
-  assert (err == 0);
-  assert (key);
+  if (private_key_mode)
+    {
+      err = nvc_get_private_key (pk, &key);
+      assert (err == 0);
+      assert (key);
 
-  if (verbose)
-    gcry_sexp_dump (key);
+      if (verbose)
+        gcry_sexp_dump (key);
 
-  gcry_sexp_release (key);
+      gcry_sexp_release (key);
+    }
+  else
+    {
+      err = nvc_get_private_key (pk, &key);
+      assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY);
+    }
 }
 
 
 void
-test_iteration (pkc_t pk)
+test_iteration (nvc_t pk)
 {
   int i;
-  pke_t e;
+  nve_t e;
 
   i = 0;
-  for (e = pkc_first (pk); e; e = pke_next (e))
+  for (e = nvc_first (pk); e; e = nve_next (e))
     i++;
   assert (i == 4);
 
   i = 0;
-  for (e = pkc_lookup (pk, "Comment:");
+  for (e = nvc_lookup (pk, "Comment:");
        e;
-       e = pke_next_value (e, "Comment:"))
+       e = nve_next_value (e, "Comment:"))
     i++;
   assert (i == 3);
 }
 
 
 void
-test_whitespace (pkc_t pk)
+test_whitespace (nvc_t pk)
 {
-  pke_t e;
+  nve_t e;
 
-  e = pkc_lookup (pk, "One:");
+  e = nvc_lookup (pk, "One:");
   assert (e);
-  assert (strcmp (pke_value (e), "WithoutWhitespace") == 0);
+  assert (strcmp (nve_value (e), "WithoutWhitespace") == 0);
 
-  e = pkc_lookup (pk, "Two:");
+  e = nvc_lookup (pk, "Two:");
   assert (e);
-  assert (strcmp (pke_value (e), "With Whitespace") == 0);
+  assert (strcmp (nve_value (e), "With Whitespace") == 0);
 
-  e = pkc_lookup (pk, "Three:");
+  e = nvc_lookup (pk, "Three:");
   assert (e);
-  assert (strcmp (pke_value (e),
+  assert (strcmp (nve_value (e),
                   "Blank lines in continuations encode newlines.\n"
                   "Next paragraph.") == 0);
 }
@@ -110,7 +130,7 @@ test_whitespace (pkc_t pk)
 struct
 {
   char *value;
-  void (*test_func) (pkc_t);
+  void (*test_func) (nvc_t);
 } tests[] =
   {
     {
@@ -193,7 +213,7 @@ struct
 
 
 static char *
-pkc_to_string (pkc_t pk)
+nvc_to_string (nvc_t pk)
 {
   gpg_error_t err;
   char *buf;
@@ -203,7 +223,7 @@ pkc_to_string (pkc_t pk)
   sink = es_fopenmem (0, "rw");
   assert (sink);
 
-  err = pkc_write (pk, sink);
+  err = nvc_write (pk, sink);
   assert (err == 0);
 
   len = es_ftell (sink);
@@ -226,7 +246,7 @@ void
 run_tests (void)
 {
   gpg_error_t err;
-  pkc_t pk;
+  nvc_t pk;
 
   int i;
   for (i = 0; i < DIM (tests); i++)
@@ -240,17 +260,20 @@ run_tests (void)
                         0, dummy_realloc, dummy_free, "r");
       assert (source);
 
-      err = pkc_parse (&pk, NULL, source);
+      if (private_key_mode)
+        err = nvc_parse_private_key (&pk, NULL, source);
+      else
+        err = nvc_parse (&pk, NULL, source);
       assert (err == 0);
       assert (pk);
 
       if (verbose)
        {
-         err = pkc_write (pk, es_stderr);
+         err = nvc_write (pk, es_stderr);
          assert (err == 0);
        }
 
-      buf = pkc_to_string (pk);
+      buf = nvc_to_string (pk);
       assert (memcmp (tests[i].value, buf, len) == 0);
 
       es_fclose (source);
@@ -259,7 +282,7 @@ run_tests (void)
       if (tests[i].test_func)
        tests[i].test_func (pk);
 
-      pkc_release (pk);
+      nvc_release (pk);
     }
 }
 
@@ -268,106 +291,115 @@ void
 run_modification_tests (void)
 {
   gpg_error_t err;
-  pkc_t pk;
+  nvc_t pk;
   gcry_sexp_t key;
   char *buf;
 
-  pk = pkc_new ();
+  pk = my_nvc_new ();
   assert (pk);
 
-  pkc_set (pk, "Foo:", "Bar");
-  buf = pkc_to_string (pk);
+  nvc_set (pk, "Foo:", "Bar");
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Bar\n") == 0);
   xfree (buf);
 
-  pkc_set (pk, "Foo:", "Baz");
-  buf = pkc_to_string (pk);
+  nvc_set (pk, "Foo:", "Baz");
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Baz\n") == 0);
   xfree (buf);
 
-  pkc_set (pk, "Bar:", "Bazzel");
-  buf = pkc_to_string (pk);
+  nvc_set (pk, "Bar:", "Bazzel");
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
   xfree (buf);
 
-  pkc_add (pk, "Foo:", "Bar");
-  buf = pkc_to_string (pk);
+  nvc_add (pk, "Foo:", "Bar");
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
   xfree (buf);
 
-  pkc_add (pk, "DontExistYet:", "Bar");
-  buf = pkc_to_string (pk);
+  nvc_add (pk, "DontExistYet:", "Bar");
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\nDontExistYet: Bar\n")
          == 0);
   xfree (buf);
 
-  pkc_delete (pk, pkc_lookup (pk, "DontExistYet:"));
-  buf = pkc_to_string (pk);
+  nvc_delete (pk, nvc_lookup (pk, "DontExistYet:"));
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
   xfree (buf);
 
-  pkc_delete (pk, pke_next_value (pkc_lookup (pk, "Foo:"), "Foo:"));
-  buf = pkc_to_string (pk);
+  nvc_delete (pk, nve_next_value (nvc_lookup (pk, "Foo:"), "Foo:"));
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
   xfree (buf);
 
-  pkc_delete (pk, pkc_lookup (pk, "Foo:"));
-  buf = pkc_to_string (pk);
+  nvc_delete (pk, nvc_lookup (pk, "Foo:"));
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Bar: Bazzel\n") == 0);
   xfree (buf);
 
-  pkc_delete (pk, pkc_first (pk));
-  buf = pkc_to_string (pk);
+  nvc_delete (pk, nvc_first (pk));
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "") == 0);
   xfree (buf);
 
-  pkc_set (pk, "Foo:", "A really long value spanning across multiple lines"
+  nvc_set (pk, "Foo:", "A really long value spanning across multiple lines"
           " that has to be wrapped at a convenient space.");
-  buf = pkc_to_string (pk);
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: A really long value spanning across multiple"
                  " lines that has to be\n  wrapped at a convenient space.\n")
          == 0);
   xfree (buf);
 
-  pkc_set (pk, "Foo:", "XA really long value spanning across multiple lines"
+  nvc_set (pk, "Foo:", "XA really long value spanning across multiple lines"
           " that has to be wrapped at a convenient space.");
-  buf = pkc_to_string (pk);
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: XA really long value spanning across multiple"
                  " lines that has to\n  be wrapped at a convenient space.\n")
          == 0);
   xfree (buf);
 
-  pkc_set (pk, "Foo:", "XXXXA really long value spanning across multiple lines"
+  nvc_set (pk, "Foo:", "XXXXA really long value spanning across multiple lines"
           " that has to be wrapped at a convenient space.");
-  buf = pkc_to_string (pk);
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: XXXXA really long value spanning across multiple"
                  " lines that has\n  to be wrapped at a convenient space.\n")
          == 0);
   xfree (buf);
 
-  pkc_set (pk, "Foo:", "Areallylongvaluespanningacrossmultiplelines"
+  nvc_set (pk, "Foo:", "Areallylongvaluespanningacrossmultiplelines"
           "thathastobewrappedataconvenientspacethatisnotthere.");
-  buf = pkc_to_string (pk);
+  buf = nvc_to_string (pk);
   assert (strcmp (buf, "Foo: Areallylongvaluespanningacrossmultiplelinesthat"
                  "hastobewrappedataco\n nvenientspacethatisnotthere.\n")
          == 0);
   xfree (buf);
-  pkc_release (pk);
+  nvc_release (pk);
 
-  pk = pkc_new ();
+  pk = my_nvc_new ();
   assert (pk);
 
   err = gcry_sexp_build (&key, NULL, "(hello world)");
   assert (err == 0);
   assert (key);
 
-  err = pkc_set_private_key (pk, key);
+  if (private_key_mode)
+    {
+      err = nvc_set_private_key (pk, key);
+      assert (err == 0);
+
+      buf = nvc_to_string (pk);
+      assert (strcmp (buf, "Key: (hello world)\n") == 0);
+      xfree (buf);
+    }
+  else
+    {
+      err = nvc_set_private_key (pk, key);
+      assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY);
+    }
   gcry_sexp_release (key);
-  assert (err == 0);
-  buf = pkc_to_string (pk);
-  assert (strcmp (buf, "Key: (hello world)\n") == 0);
-  xfree (buf);
-  pkc_release (pk);
+  nvc_release (pk);
 }
 
 
@@ -380,7 +412,7 @@ convert (const char *fname)
   char *buf;
   size_t buflen;
   struct stat st;
-  pkc_t pk;
+  nvc_t pk;
 
   source = es_fopen (fname, "rb");
   if (source == NULL)
@@ -403,13 +435,13 @@ convert (const char *fname)
       exit (1);
     }
 
-  pk = pkc_new ();
+  pk = my_nvc_new ();
   assert (pk);
 
-  err = pkc_set_private_key (pk, key);
+  err = nvc_set_private_key (pk, key);
   assert (err == 0);
 
-  err = pkc_write (pk, es_stdout);
+  err = nvc_write (pk, es_stdout);
   assert (err == 0);
 
   return;
@@ -426,8 +458,8 @@ parse (const char *fname)
   gpg_error_t err;
   estream_t source;
   char *buf;
-  pkc_t pk_a, pk_b;
-  pke_t e;
+  nvc_t pk_a, pk_b;
+  nve_t e;
   int line;
 
   source = es_fopen (fname, "rb");
@@ -437,7 +469,10 @@ parse (const char *fname)
       exit (1);
     }
 
-  err = pkc_parse (&pk_a, &line, source);
+  if (private_key_mode)
+    err = nvc_parse_private_key (&pk_a, &line, source);
+  else
+    err = nvc_parse (&pk_a, &line, source);
   if (err)
     {
       fprintf (stderr, "failed to parse %s line %d: %s\n",
@@ -445,36 +480,36 @@ parse (const char *fname)
       exit (1);
     }
 
-  buf = pkc_to_string (pk_a);
+  buf = nvc_to_string (pk_a);
   xfree (buf);
 
-  pk_b = pkc_new ();
+  pk_b = my_nvc_new ();
   assert (pk_b);
 
-  for (e = pkc_first (pk_a); e; e = pke_next (e))
+  for (e = nvc_first (pk_a); e; e = nve_next (e))
     {
       gcry_sexp_t key = NULL;
 
-      if (strcasecmp (pke_name (e), "Key:") == 0)
+      if (private_key_mode && !strcasecmp (nve_name (e), "Key:"))
        {
-         err = pkc_get_private_key (pk_a, &key);
+         err = nvc_get_private_key (pk_a, &key);
          if (err)
            key = NULL;
        }
 
       if (key)
        {
-         err = pkc_set_private_key (pk_b, key);
+         err = nvc_set_private_key (pk_b, key);
          assert (err == 0);
        }
       else
        {
-         err = pkc_add (pk_b, pke_name (e), pke_value (e));
+         err = nvc_add (pk_b, nve_name (e), nve_value (e));
          assert (err == 0);
        }
     }
 
-    buf = pkc_to_string (pk_b);
+    buf = nvc_to_string (pk_b);
     if (verbose)
       fprintf (stdout, "%s", buf);
     xfree (buf);
@@ -487,7 +522,8 @@ print_usage (void)
   fprintf (stderr,
           "usage: t-private-keys [--verbose]"
           " [--convert <private-key-file>"
-          " || --parse <extended-private-key-file>]\n");
+          " || --parse-key <extended-private-key-file>"
+           " || --parse <file> ]\n");
   exit (2);
 }
 
@@ -495,7 +531,7 @@ print_usage (void)
 int
 main (int argc, char **argv)
 {
-  enum { TEST, CONVERT, PARSE } command = TEST;
+  enum { TEST, CONVERT, PARSE, PARSEKEY } command = TEST;
 
   if (argc)
     { argc--; argv++; }
@@ -513,6 +549,14 @@ main (int argc, char **argv)
        print_usage ();
     }
 
+  if (argc && !strcmp (argv[0], "--parse-key"))
+    {
+      command = PARSEKEY;
+      argc--; argv++;
+      if (argc != 1)
+       print_usage ();
+    }
+
   if (argc && !strcmp (argv[0], "--parse"))
     {
       command = PARSE;
@@ -526,12 +570,20 @@ main (int argc, char **argv)
     case TEST:
       run_tests ();
       run_modification_tests ();
+      private_key_mode = 1;
+      run_tests ();
+      run_modification_tests ();
       break;
 
     case CONVERT:
       convert (*argv);
       break;
 
+    case PARSEKEY:
+      private_key_mode = 1;
+      parse (*argv);
+      break;
+
     case PARSE:
       parse (*argv);
       break;
diff --git a/common/t-recsel.c b/common/t-recsel.c
new file mode 100644 (file)
index 0000000..fe2a7b9
--- /dev/null
@@ -0,0 +1,405 @@
+/* t-recsel.c - Module test for recsel.c
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "init.h"
+#include "recsel.h"
+
+#define PGM  "t-recsel"
+
+#define pass()  do { ; } while(0)
+#define fail(a,e)  do { log_error ("line %d: test %d failed: %s\n",     \
+                                   __LINE__, (a), gpg_strerror ((e)));  \
+                       exit (1);                                        \
+                    } while(0)
+
+static int verbose;
+static int debug;
+
+
+#define FREEEXPR() do { recsel_release (se); se = NULL; } while (0)
+#define ADDEXPR(a) do {                         \
+    err = recsel_parse_expr (&se, (a));         \
+    if (err)                                    \
+      fail (0, err);                            \
+  } while (0)
+
+
+static const char *
+test_1_getval (void *cookie, const char *name)
+{
+  if (strcmp (name, "uid"))
+    fail (0, 0);
+  return cookie;
+}
+
+static void
+run_test_1 (void)
+{
+  static const char *expr[] = {
+    "uid =~ Alfa",
+    "&& uid !~   Test  ",
+    "|| uid =~  Alpha",
+    " uid  !~ Test"
+  };
+  gpg_error_t err;
+  recsel_expr_t se = NULL;
+  int i;
+
+  for (i=0; i < DIM (expr); i++)
+    {
+      err = recsel_parse_expr (&se, expr[i]);
+      if (err)
+        fail (i, err);
+    }
+
+  if (debug)
+    recsel_dump (se);
+
+  /* The example from recsel.c in several variants. */
+  if (!recsel_select (se, test_1_getval, "Alfa"))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, "Alpha"))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, "Alfa Test"))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, "Alpha Test"))
+    fail (0, 0);
+
+  /* Some modified versions from above.  */
+  if (!recsel_select (se, test_1_getval, " AlfA Tes"))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, " AlfA Tes "))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, " Tes  AlfA"))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, "TesAlfA"))
+    fail (0, 0);
+
+  /* Simple cases. */
+  if (recsel_select (se, NULL, NULL))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, NULL))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, ""))
+    fail (0, 0);
+
+  FREEEXPR();
+}
+
+
+/* Same as test1 but using a combined expression.. */
+static void
+run_test_1b (void)
+{
+  gpg_error_t err;
+  recsel_expr_t se = NULL;
+
+  err = recsel_parse_expr
+    (&se, "uid =~ Alfa && uid !~   Test  || uid =~  Alpha && uid  !~ Test" );
+  if (err)
+    fail (0, err);
+
+  if (debug)
+    recsel_dump (se);
+
+  /* The example from recsel.c in several variants. */
+  if (!recsel_select (se, test_1_getval, "Alfa"))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, "Alpha"))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, "Alfa Test"))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, "Alpha Test"))
+    fail (0, 0);
+
+  /* Some modified versions from above.  */
+  if (!recsel_select (se, test_1_getval, " AlfA Tes"))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, " AlfA Tes "))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, " Tes  AlfA"))
+    fail (0, 0);
+  if (!recsel_select (se, test_1_getval, "TesAlfA"))
+    fail (0, 0);
+
+  /* Simple cases. */
+  if (recsel_select (se, NULL, NULL))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, NULL))
+    fail (0, 0);
+  if (recsel_select (se, test_1_getval, ""))
+    fail (0, 0);
+
+  FREEEXPR();
+}
+
+
+static const char *
+test_2_getval (void *cookie, const char *name)
+{
+  if (!strcmp (name, "uid"))
+    return "foo@example.org";
+  else if (!strcmp (name, "keyid"))
+    return "0x12345678";
+  else if (!strcmp (name, "zero"))
+    return "0";
+  else if (!strcmp (name, "one"))
+    return "1";
+  else if (!strcmp (name, "blanks"))
+    return "    ";
+  else if (!strcmp (name, "letters"))
+    return "abcde";
+  else
+    return cookie;
+}
+
+static void
+run_test_2 (void)
+{
+  gpg_error_t err;
+  recsel_expr_t se = NULL;
+
+  ADDEXPR ("uid = foo@example.org");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("uid = Foo@example.org");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("-c uid = Foo@example.org");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("uid =~ foo@example.org");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("uid =~ Foo@example.org");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("-c uid =~ Foo@example.org");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("uid !~ foo@example.org");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("uid !~ Foo@example.org");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("-c uid !~ Foo@example.org");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("uid =~ @");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("uid =~ @");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("keyid == 0x12345678");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("keyid != 0x12345678");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("keyid >= 0x12345678");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("keyid <= 0x12345678");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("keyid > 0x12345677");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("keyid < 0x12345679");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("keyid > 0x12345678");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("keyid < 0x12345678");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+
+  FREEEXPR();
+  ADDEXPR ("uid -n");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("uid -z");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("nothing -z");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("nothing -n");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("blanks -n");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("blanks -z");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("letters -n");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("letters -z");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+
+  FREEEXPR();
+  ADDEXPR ("nothing -f");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("nothing -t");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("zero -f");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("zero -t");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("one -t");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("one -f");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("blanks -f");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("blanks -t");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+  FREEEXPR();
+  ADDEXPR ("letter -f");
+  if (!recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+  FREEEXPR();
+  ADDEXPR ("letters -t");
+  if (recsel_select (se, test_2_getval, NULL))
+    fail (0, 0);
+
+
+  FREEEXPR();
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+
+  log_set_prefix (PGM, GPGRT_LOG_WITH_PREFIX);
+  init_common_subsystems (&argc, &argv);
+
+  if (argc)
+    { argc--; argv++; }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: " PGM " [options]\n"
+                 "Options:\n"
+                 "  --verbose       print timings etc.\n"
+                 "  --debug         flyswatter\n",
+                 stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        {
+          log_error ("unknown option '%s'\n", *argv);
+          exit (2);
+        }
+    }
+
+  run_test_1 ();
+  run_test_1b ();
+  run_test_2 ();
+  /* Fixme: We should add test for complex conditions.  */
+
+  return 0;
+}
index 4f4555e..ccadf02 100644 (file)
@@ -223,6 +223,7 @@ test_strconcat (void)
     fail (0);
   else if (errno != EINVAL)
     fail (0);
+  xfree (out);
 
 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute.  */
   out = strconcat (NULL);
@@ -232,6 +233,8 @@ test_strconcat (void)
   out = strconcat (NULL, NULL);
   if (!out || *out)
     fail (1);
+  xfree (out);
+
   out = strconcat ("", NULL);
   if (!out || *out)
     fail (1);
@@ -283,6 +286,7 @@ test_xstrconcat (void)
                    "1", "2", "3", "4", "5", "6", "7", NULL);
   if (!out)
     fail (0);
+  xfree (out);
 
 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute.  */
   out = xstrconcat (NULL);
@@ -292,6 +296,8 @@ test_xstrconcat (void)
   out = xstrconcat (NULL, NULL);
   if (!out)
     fail (1);
+  xfree (out);
+
   out = xstrconcat ("", NULL);
   if (!out || *out)
     fail (1);
@@ -534,6 +540,7 @@ test_strsplit (void)
             fail (tidx * 1000 + i + 1);
           }
 
+      xfree (fields);
       xfree (s2);
     }
 }
index b033905..e49d5a7 100644 (file)
@@ -67,6 +67,8 @@ test_strlist_rev (void)
     fail (2);
   if (s->next->next->next)
     fail (2);
+
+  free_strlist (s);
 }
 
 
index c84847a..eb7a3fd 100644 (file)
 #include <gpg-error.h> /* We need gpg_error_t and estream. */
 
 /* These error codes are used but not defined in the required
-   libgpg-error version.  Define them here. */
-/* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21) */
-#if GPG_ERROR_VERSION_NUMBER < 0x011600  /* 1.22 */
-# define GPG_ERR_DB_CORRUPTED  218
-#endif /* gpg_error < 1.22 */
+ * libgpg-error version.  Define them here.
+ * Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
+ */
+
 
 /* Hash function used with libksba. */
 #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
index 05aa0ea..54bd5d4 100644 (file)
@@ -35,7 +35,7 @@
 #include <assert.h>
 
 #include "util.h"
-
+#include "zb32.h"
 
 /* Zooko's base32 variant. See RFC-6189 and
    http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
index 1b8a6fc..9bc32ee 100644 (file)
@@ -1,6 +1,6 @@
 # configure.ac - for GnuPG 2.1
 # Copyright (C) 1998-2012 Free Software Foundation, Inc.
-# Copyright (C) 1998-2015 Werner Koch
+# Copyright (C) 1998-2016 Werner Koch
 #
 # This file is part of GnuPG.
 #
@@ -28,7 +28,7 @@ min_automake_version="1.14"
 m4_define([mym4_package],[gnupg])
 m4_define([mym4_major], [2])
 m4_define([mym4_minor], [1])
-m4_define([mym4_micro], [13])
+m4_define([mym4_micro], [14])
 
 # To start a new development series, i.e a new major or minor number
 # you need to mark an arbitrary commit before the first beta release
@@ -49,23 +49,22 @@ m4_define([mym4_revision_dec], m4_argn(8, mym4_verslist))
 m4_esyscmd([echo ]mym4_version[>VERSION])
 AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org])
 
-# Note that for Windows we require version 1.22
-NEED_GPG_ERROR_VERSION=1.21
+NEED_GPG_ERROR_VERSION=1.24
 
 NEED_LIBGCRYPT_API=1
-NEED_LIBGCRYPT_VERSION=1.6.0
+NEED_LIBGCRYPT_VERSION=1.7.0
 
 NEED_LIBASSUAN_API=2
-NEED_LIBASSUAN_VERSION=2.4.1
+NEED_LIBASSUAN_VERSION=2.4.3
 
 NEED_KSBA_API=1
-NEED_KSBA_VERSION=1.2.0
+NEED_KSBA_VERSION=1.3.4
 
 NEED_NTBTLS_API=1
 NEED_NTBTLS_VERSION=0.1.0
 
 NEED_NPTH_API=1
-NEED_NPTH_VERSION=0.91
+NEED_NPTH_VERSION=1.2
 
 
 NEED_GNUTLS_VERSION=3.0
@@ -130,6 +129,7 @@ GNUPG_BUILD_PROGRAM(tools, yes)
 GNUPG_BUILD_PROGRAM(doc, yes)
 GNUPG_BUILD_PROGRAM(symcryptrun, no)
 GNUPG_BUILD_PROGRAM(gpgtar, yes)
+GNUPG_BUILD_PROGRAM(wks-tools, no)
 
 AC_SUBST(PACKAGE)
 AC_SUBST(PACKAGE_GT)
@@ -1670,6 +1670,7 @@ AM_CONDITIONAL(BUILD_TOOLS,       test "$build_tools" = "yes")
 AM_CONDITIONAL(BUILD_DOC,         test "$build_doc" = "yes")
 AM_CONDITIONAL(BUILD_SYMCRYPTRUN, test "$build_symcryptrun" = "yes")
 AM_CONDITIONAL(BUILD_GPGTAR,      test "$build_gpgtar" = "yes")
+AM_CONDITIONAL(BUILD_WKS_TOOLS,   test "$build_wks_tools" = "yes")
 
 AM_CONDITIONAL(ENABLE_CARD_SUPPORT, test "$card_support" = yes)
 AM_CONDITIONAL(NO_TRUST_MODELS,     test "$use_trust_models" = no)
@@ -1903,7 +1904,9 @@ tools/gpg-zip
 tools/Makefile
 doc/Makefile
 tests/Makefile
+tests/gpgscm/Makefile
 tests/openpgp/Makefile
+tests/migrations/Makefile
 tests/pkits/Makefile
 g10/gpg.w32-manifest
 ])
@@ -1925,6 +1928,7 @@ echo "
         G13:       $build_g13
         Dirmngr:   $build_dirmngr
         Gpgtar:    $build_gpgtar
+        WKS tools: $build_wks_tools
 
         Protect tool:      $show_gnupg_protect_tool_pgm
         LDAP wrapper:      $show_gnupg_dirmngr_ldap_pgm
index 941ad4f..a512e9a 100644 (file)
@@ -744,7 +744,7 @@ http_session_set_log_cb (http_session_t sess,
 \f
 /* Start a HTTP retrieval and on success store at R_HD a context
    pointer for completing the request and to wait for the response.
-   If HTTPHOST is not NULL it is used hor the Host header instead of a
+   If HTTPHOST is not NULL it is used for the Host header instead of a
    Host header derived from the URL. */
 gpg_error_t
 http_open (http_t *r_hd, http_req_t reqtype, const char *url,
index 636eaf7..bcc1750 100644 (file)
@@ -1207,12 +1207,16 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
       pattern = fprbuf;
       break;
     case KEYDB_SEARCH_MODE_FPR16:
-      bin2hex (desc.u.fpr, 16, fprbuf);
+      fprbuf[0] = '0';
+      fprbuf[1] = 'x';
+      bin2hex (desc.u.fpr, 16, fprbuf+2);
       pattern = fprbuf;
       break;
     case KEYDB_SEARCH_MODE_FPR20:
     case KEYDB_SEARCH_MODE_FPR:
-      bin2hex (desc.u.fpr, 20, fprbuf);
+      fprbuf[0] = '0';
+      fprbuf[1] = 'x';
+      bin2hex (desc.u.fpr, 20, fprbuf+2);
       pattern = fprbuf;
       break;
     default:
index 00d0c4b..adee04f 100644 (file)
@@ -73,6 +73,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
   estream_t fp = NULL;
   char *request_buffer = NULL;
 
+ once_more:
   /* Note that we only use the system provided certificates with the
    * fetch command.  */
   err = http_session_new (&session, NULL, NULL, HTTP_FLAG_TRUST_SYS);
@@ -81,7 +82,6 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
   http_session_set_log_cb (session, cert_log_cb);
 
   *r_fp = NULL;
- once_more:
   err = http_open (&http,
                    HTTP_REQ_GET,
                    url,
@@ -146,6 +146,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
                 url = request_buffer;
                 http_close (http, 0);
                 http = NULL;
+                http_session_release (session);
                 goto once_more;
               }
             err = gpg_error_from_syserror ();
index 6eb6f1b..db6f5a8 100644 (file)
@@ -274,14 +274,12 @@ strcpy_escaped_plus (char *d, const unsigned char *s)
 }
 
 
-/* This fucntion returns true if a Tor server is running.  The sattus
+/* This function returns true if a Tor server is running.  The sattus
    is cached for the current conenction.  */
 static int
 is_tor_running (ctrl_t ctrl)
 {
-#if ASSUAN_VERSION_NUMBER >= 0x020402
-  /* Check whether we can connect to the proxy.  We use a
-     special feature introduced with libassuan 2.4.2.  */
+  /* Check whether we can connect to the proxy.  */
 
   if (!ctrl || !ctrl->server_local)
     return 0; /* Ooops.  */
@@ -300,9 +298,6 @@ is_tor_running (ctrl_t ctrl)
         }
     }
   return (ctrl->server_local->tor_state > 0);
-#else /* Libassuan < 2.4.2 */
-  return 0;  /* We don't know.  */
-#endif
 }
 
 
@@ -799,9 +794,10 @@ cmd_dns_cert (assuan_context_t ctx, char *line)
 
 \f
 static const char hlp_wkd_get[] =
-  "WKD_GET <user_id>\n"
+  "WKD_GET [--submission-address] <user_id>\n"
   "\n"
-  "Return the key for <user_id> from a Web Key Directory.\n";
+  "Return the key or the submission address for <user_id>\n"
+  "from a Web Key Directory.";
 static gpg_error_t
 cmd_wkd_get (assuan_context_t ctx, char *line)
 {
@@ -812,7 +808,9 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
   char sha1buf[20];
   char *uri = NULL;
   char *encodedhash = NULL;
+  int opt_submission_addr;
 
+  opt_submission_addr = has_option (line, "--submission-address");
   line = skip_options (line);
 
   mbox = mailbox_from_userid (line);
@@ -831,11 +829,21 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
       goto leave;
     }
 
-  uri = strconcat ("https://",
-                   domain,
-                   "/.well-known/openpgpkey/hu/",
-                   encodedhash,
-                   NULL);
+  if (opt_submission_addr)
+    {
+      uri = strconcat ("https://",
+                       domain,
+                       "/.well-known/openpgpkey/submission-address",
+                       NULL);
+    }
+  else
+    {
+      uri = strconcat ("https://",
+                       domain,
+                       "/.well-known/openpgpkey/hu/",
+                       encodedhash,
+                       NULL);
+    }
   if (!uri)
     {
       err = gpg_error_from_syserror ();
@@ -848,7 +856,8 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
 
     outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
     if (!outfp)
-      err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
+      err = set_error (GPG_ERR_ASS_GENERAL,
+                       "error setting up a data stream");
     else
       {
         err = ks_action_fetch (ctrl, uri, outfp);
index 100ce0d..145b47a 100644 (file)
@@ -222,6 +222,8 @@ check_ldap_escape_filter (int test_count, struct test_ldap_escape_filter *test)
              test->filter, result, test->result);
       fail (test_count * 1000);
     }
+
+  xfree (result);
 }
 
 static void
index d2168d6..94e65d8 100644 (file)
@@ -46,6 +46,8 @@ are
  - scd     :: The scdaemon component
  - ccid    :: The CCID driver in scdaemon
  - dirmngr :: The dirmngr component
+ - wks     :: The web key service tools
+ - tools   :: Other code in tools
  - w32     :: Windows related code
  - po      :: Translations
  - build   :: Changes to the build system
index bc06cd5..52ac398 100644 (file)
@@ -32,7 +32,7 @@ helpfiles = help.txt help.be.txt help.ca.txt help.cs.txt              \
             help.pt_BR.txt help.ro.txt help.ru.txt help.sk.txt         \
             help.sv.txt help.tr.txt help.zh_CN.txt help.zh_TW.txt
 
-EXTRA_DIST = samplekeys.asc mksamplekeys \
+EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem qualified.txt \
             gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png \
             gnupg-module-overview.png gnupg-module-overview.pdf \
              gnupg-card-architecture.png gnupg-card-architecture.pdf \
@@ -46,7 +46,7 @@ BUILT_SOURCES = gnupg-module-overview.png gnupg-module-overview.pdf \
 
 info_TEXINFOS = gnupg.texi
 
-dist_pkgdata_DATA = qualified.txt com-certs.pem $(helpfiles)
+dist_pkgdata_DATA =  $(helpfiles)
 
 nobase_dist_doc_DATA = FAQ DETAILS HACKING DCO TRANSLATE OpenPGP KEYSERVER \
                        $(examples)
index 37774dd..cd5d751 100644 (file)
@@ -815,7 +815,7 @@ it by adding this to your init script:
 @example
 unset SSH_AGENT_PID
 if [ "$@{gnupg_SSH_AUTH_SOCK_by:-0@}" -ne $$ ]; then
-  export SSH_AUTH_SOCK="$@{HOME@}/.gnupg/S.gpg-agent.ssh"
+  export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
 fi
 @end example
 @end cartouche
index be80450..38f417e 100644 (file)
@@ -233,7 +233,7 @@ read from STDIN.  If only a one argument is given, it is expected to
 be a complete signature.
 
 With more than 1 argument, the first should be a detached signature
-and the remaining files ake up the the signed data. To read the signed
+and the remaining files make up the the signed data. To read the signed
 data from STDIN, use @samp{-} as the second filename.  For security
 reasons a detached signature cannot read the signed material from
 STDIN without denoting it in the above way.
@@ -281,9 +281,10 @@ List all keys from the public keyrings, or just the keys given on the
 command line.
 
 Avoid using the output of this command in scripts or other programs as
-it is likely to change as GnuPG changes. See @option{--with-colons} for a
-machine-parseable key listing command that is appropriate for use in
-scripts and other programs.
+it is likely to change as GnuPG changes.  See @option{--with-colons}
+for a machine-parseable key listing command that is appropriate for
+use in scripts and other programs.  Never use the regular output for
+scripts - it is only for human consumption.
 
 @item --list-secret-keys
 @itemx -K
@@ -291,7 +292,7 @@ scripts and other programs.
 List all keys from the secret keyrings, or just the ones given on the
 command line. A @code{#} after the letters @code{sec} means that the
 secret key is not usable (for example, if it was created via
-@option{--export-secret-subkeys}).
+@option{--export-secret-subkeys}).  See also @option{--list-keys}.
 
 @item --list-sigs
 @opindex list-sigs
@@ -569,7 +570,7 @@ Use the source, Luke :-). The output format is still subject to change.
 
 
 @item --enarmor
-@item --dearmor
+@itemx --dearmor
 @opindex enarmor
 @opindex dearmor
 Pack or unpack an arbitrary input into/from an OpenPGP ASCII armor.
@@ -1040,6 +1041,15 @@ the interactive sub-command @code{adduid} of @option{--edit-key} the
 white space removed, it is expected to be UTF-8 encoded, and no checks
 on its form are applied.
 
+@item --quick-revuid  @var{user-id} @var{user-id-to-revoke}
+@opindex quick-revuid
+This command revokes a User ID on an existing key.  It cannot be used
+to revoke the last User ID on key (some non-revoked User ID must
+remain), with revocation reason ``User ID is no longer valid''.  If
+you want to specify a different revocation reason, or to supply
+supplementary revocation text, you should use the interactive
+sub-command @code{revuid} of @option{--edit-key}.
+
 @item --passwd @var{user_id}
 @opindex passwd
 Change the passphrase of the secret key belonging to the certificate
@@ -1361,6 +1371,10 @@ Note that this adds a keyring to the current list. If the intent is to
 use the specified keyring alone, use @option{--keyring} along with
 @option{--no-default-keyring}.
 
+If the the option @option{--no-keyring} has been used no keyrings will
+be used at all.
+
+
 @item --secret-keyring @code{file}
 @opindex secret-keyring
 This is an obsolete option and ignored.  All secret keys are stored in
@@ -2023,6 +2037,22 @@ limited countermeasure against traffic analysis. If this option or
 @option{--recipient} is not specified, GnuPG asks for the user ID unless
 @option{--default-recipient} is given.
 
+@item --recipient-file @var{file}
+@itemx -f
+@opindex recipient-file
+This option is similar to @option{--recipient} except that it
+encrypts to a key stored in the given file.  @var{file} must be the
+name of a file containing exactly one key.  @command{gpg} assumes that
+the key in this file is fully valid.
+
+@item --hidden-recipient-file @var{file}
+@itemx -F
+@opindex hidden-recipient-file
+This option is similar to @option{--hidden-recipient} except that it
+encrypts to a key stored in the given file.  @var{file} must be the
+name of a file containing exactly one key.  @command{gpg} assumes that
+the key in this file is fully valid.
+
 @item --encrypt-to @code{name}
 @opindex encrypt-to
 Same as @option{--recipient} but this one is intended for use in the
@@ -2041,11 +2071,6 @@ recipients given either by use of @option{--recipient} or by the asked user id.
 No trust checking is performed for these user ids and even disabled
 keys can be used.
 
-@item --encrypt-to-default-key
-@opindex encrypt-to-default-key
-If the default secret key is taken from @option{--default-key}, then
-also encrypt to that key.
-
 @item --no-encrypt-to
 @opindex no-encrypt-to
 Disable the use of all @option{--encrypt-to} and
@@ -2179,6 +2204,18 @@ opposite meaning. The options are:
   subkey. Defaults to no for regular @option{--import} and to yes for
   keyserver @option{--recv-keys}.
 
+  @item import-show
+  Show a listing of the key as imported right before it is stored.
+  This can be combined with the option @option{--dry-run} to only look
+  at keys.
+
+  @item import-export
+  Run the entire import code but instead of storing the key to the
+  local keyring write it to the output.  The export options
+  @option{export-pka} and @option{export-dane} affect the output.  This
+  option can be used to remove all invalid parts from a key without the
+  need to store it.
+
   @item merge-only
   During import, allow key updates to existing keys, but do not allow
   any new keys to be imported. Defaults to no.
@@ -2198,6 +2235,47 @@ opposite meaning. The options are:
   Defaults to no.
 @end table
 
+@item --import-filter @code{@var{name}=@var{expr}}
+@itemx --export-filter @code{@var{name}=@var{expr}}
+@opindex import-filter
+@opindex export-filter
+These options define an import/export filter which are applied to the
+imported/exported keyblock right before it will be stored/written.
+@var{name} defines the type of filter to use, @var{expr} the
+expression to evaluate.  The option can be used several times which
+then appends more expression to the same @var{name}.
+
+@noindent
+The available filter types are:
+
+@table @asis
+
+  @item keep-uid
+  This filter will keep a user id packet and its dependent packets in
+  the keyblock if the expression evaluates to true.
+
+@end table
+
+For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
+The property names for the expressions depend on the actual filter
+type and are indicated in the following table.
+
+The available properties are:
+
+@table @asis
+
+  @item uid
+  A string with the user id.  (keep-uid)
+
+  @item mbox
+  The addr-spec part of a user id with mailbox or the empty string.
+  (keep-uid)
+
+  @item primary
+  Boolean indicating whether the user id is the primary one.  (keep-uid)
+
+@end table
+
 @item --export-options @code{parameters}
 @opindex export-options
 This is a space or comma delimited string that gives options for
@@ -2244,6 +2322,18 @@ opposite meaning. The options are:
   most recent self-signature on each user ID. This option is the same as
   running the @option{--edit-key} command "minimize" before export except
   that the local copy of the key is not modified. Defaults to no.
+
+  @item export-pka
+  Instead of outputting the key material output PKA records suitable
+  to put into DNS zone files.  An ORIGIN line is printed before each
+  record to allow diverting the records to the corresponding zone file.
+
+  @item export-dane
+  Instead of outputting the key material output OpenPGP DANE records
+  suitable to put into DNS zone files.  An ORIGIN line is printed before
+  each record to allow diverting the records to the corresponding zone
+  file.
+
 @end table
 
 @item --with-colons
@@ -2255,20 +2345,6 @@ as it is easily machine parsed. The details of this format are
 documented in the file @file{doc/DETAILS}, which is included in the GnuPG
 source distribution.
 
-
-@item --print-pka-records
-@opindex print-pka-records
-Modify the output of the list commands to print PKA records suitable
-to put into DNS zone files.  An ORIGIN line is printed before each
-record to allow diverting the records to the corresponding zone file.
-
-@item --print-dane-records
-@opindex print-dane-records
-Modify the output of the list commands to print OpenPGP DANE records
-suitable to put into DNS zone files.  An ORIGIN line is printed before
-each record to allow diverting the records to the corresponding zone
-file.
-
 @item --fixed-list-mode
 @opindex fixed-list-mode
 Do not merge primary user ID and primary key in @option{--with-colon}
@@ -2463,6 +2539,13 @@ Reset all packet, cipher and digest options to strict RFC-4880
 behavior. Note that this is currently the same thing as
 @option{--openpgp}.
 
+@item --rfc4880bis
+@opindex rfc4880bis
+Enable experimental features from proposed updates to RFC-4880.  This
+option can be used in addition to the other compliance options.
+Warning: The behavior may change with any GnuPG release and created
+keys or data may not be usable with future GnuPG versions.
+
 @item --rfc2440
 @opindex rfc2440
 Reset all packet, cipher and digest options to strict RFC-2440
@@ -2940,6 +3023,10 @@ and do not provide alternate keyrings via @option{--keyring} or
 @option{--secret-keyring}, then GnuPG will still use the default public or
 secret keyrings.
 
+@item --no-keyring
+@opindex no-keyring
+Do not add use any keyrings even if specified as options.
+
 @item --skip-verify
 @opindex skip-verify
 Skip the signature verification step. This may be
@@ -3170,7 +3257,6 @@ current home directory (@pxref{option --homedir}).
 
 @end table
 
-@c man:.RE
 Note that on larger installations, it is useful to put predefined files
 into the directory @file{@value{SYSCONFSKELDIR}} so that
 newly created users start up with a working configuration.
@@ -3245,7 +3331,6 @@ files; They all live in in the current home directory (@pxref{option
 
 @end table
 
-@c man:.RE
 Operation is further controlled by a few environment variables:
 
 @table @asis
@@ -3338,6 +3423,123 @@ user for the filename.
 @include specify-user-id.texi
 @end ifset
 
+@mansect filter expressions
+@chapheading FILTER EXPRESSIONS
+
+The options @option{--import-filter} and @option{--export-filter} use
+expressions with this syntax (square brackets indicate an optional
+part and curly braces a repetition, white space between the elements
+are allowed):
+
+@c man:.RS
+@example
+  [lc] @{[@{flag@}] PROPNAME op VALUE [lc]@}
+@end example
+@c man:.RE
+
+The name of a property (@var{PROPNAME}) may only consist of letters,
+digits and underscores.  The description for the filter type
+describes which properties are defined.  If an undefined property is
+used it evaluates to the empty string.  Unless otherwise noted, the
+@var{VALUE} must always be given and may not be the empty string.  No
+quoting is defined for the value, thus the value may not contain the
+strings @code{&&} or @code{||}, which are used as logical connection
+operators.  The flag @code{--} can be used to remove this restriction.
+
+Numerical values are computed as long int; standard C notation
+applies.  @var{lc} is the logical connection operator; either
+@code{&&} for a conjunction or @code{||} for a disjunction.  A
+conjunction is assumed at the begin of an expression.  Conjunctions
+have higher precedence than disjunctions.  If @var{VALUE} starts with
+one of the characters used in any @var{op} a space after the
+@var{op} is required.
+
+@noindent
+The supported operators (@var{op}) are:
+
+@table @asis
+
+  @item =~
+  Substring must match.
+
+  @item  !~
+  Substring must not match.
+
+  @item  =
+  The full string must match.
+
+  @item  <>
+  The full string must not match.
+
+  @item  ==
+  The numerical value must match.
+
+  @item  !=
+  The numerical value must not match.
+
+  @item  <=
+  The numerical value of the field must be LE than the value.
+
+  @item  <
+  The numerical value of the field must be LT than the value.
+
+  @item  >=
+  The numerical value of the field must be GT than the value.
+
+  @item  >=
+  The numerical value of the field must be GE than the value.
+
+  @item  -n
+  True if value is not empty (no value allowed).
+
+  @item  -z
+  True if value is empty (no value allowed).
+
+  @item  -t
+  Alias for "PROPNAME != 0" (no value allowed).
+
+  @item  -f
+  Alias for "PROPNAME == 0" (no value allowed).
+
+@end table
+
+@noindent
+Values for @var{flag} must be space separated.  The supported flags
+are:
+
+@table @asis
+  @item --
+  @var{VALUE} spans to the end of the expression.
+  @item -c
+  The string match in this part is done case-sensitive.
+@end table
+
+The filter options concatenate several specifications for a filter of
+the same type.  For example the four options in this example:
+
+@c man:.RS
+@example
+ --import-option keep-uid="uid =~ Alfa"
+ --import-option keep-uid="&& uid !~ Test"
+ --import-option keep-uid="|| uid =~ Alpha"
+ --import-option keep-uid="uid !~ Test"
+@end example
+@c man:.RE
+
+@noindent
+which is equivalent to
+
+@c man:.RS
+@example
+ --import-option \
+  keep-uid="uid =~ Alfa" && uid !~ Test" || uid =~ Alpha" && "uid !~ Test"
+@end example
+@c man:.RE
+
+imports only the user ids of a key containing the strings "Alfa"
+or "Alpha" but not the string "test".
+
+
 @mansect return value
 @chapheading RETURN VALUE
 
index f3e2f35..b8fbed6 100644 (file)
@@ -140,6 +140,27 @@ get_date_from_files (char **files)
 }
 
 
+/* We need to escape file names for Texinfo.  */
+static void
+print_filename (const char *prefix, const char *name)
+{
+  const char *s;
+
+  fputs (prefix, stdout);
+  for (s=name; *s; s++)
+    switch (*s)
+      {
+      case '@': fputs ("@atchar{}",        stdout); break;
+      case '{': fputs ("@lbracechar{}",    stdout); break;
+      case '}': fputs ("@rbracechar{}",    stdout); break;
+      case ',': fputs ("@comma{}",         stdout); break;
+      case '\\':fputs ("@backslashchar{}", stdout); break;
+      case '#': fputs ("@hashchar{}",      stdout); break;
+      default: putchar (*s); break;
+      }
+  putchar('\n');
+}
+
 
 int
 main (int argc, char **argv)
@@ -288,17 +309,16 @@ main (int argc, char **argv)
 
   fputs ("\n@c Directories\n\n", stdout);
 
-  fputs ("@set BINDIR         " GNUPG_BINDIR        "\n"
-         "@set LIBEXECDIR     " GNUPG_LIBEXECDIR    "\n"
-         "@set LIBDIR         " GNUPG_LIBDIR        "\n"
-         "@set DATADIR        " GNUPG_DATADIR       "\n"
-         "@set SYSCONFDIR     " GNUPG_SYSCONFDIR    "\n"
-         "@set LOCALSTATEDIR  " GNUPG_LOCALSTATEDIR "\n"
-         "@set LOCALCACHEDIR  " GNUPG_LOCALSTATEDIR
-         /*                  */ "/cache/" PACKAGE_NAME "\n"
-         "@set LOCALRUNDIR    " GNUPG_LOCALSTATEDIR
-         /*                  */ "/run/"  PACKAGE_NAME "\n"
-         , stdout);
+  print_filename ("@set BINDIR         ", GNUPG_BINDIR );
+  print_filename ("@set LIBEXECDIR     ", GNUPG_LIBEXECDIR );
+  print_filename ("@set LIBDIR         ", GNUPG_LIBDIR );
+  print_filename ("@set DATADIR        ", GNUPG_DATADIR );
+  print_filename ("@set SYSCONFDIR     ", GNUPG_SYSCONFDIR );
+  print_filename ("@set LOCALSTATEDIR  ", GNUPG_LOCALSTATEDIR );
+  print_filename ("@set LOCALCACHEDIR  ", (GNUPG_LOCALSTATEDIR
+                                           "/cache/" PACKAGE_NAME));
+  print_filename ("@set LOCALRUNDIR    ", (GNUPG_LOCALSTATEDIR
+                                           "/run/"   PACKAGE_NAME));
 
   p = xstrdup (GNUPG_SYSCONFDIR);
   pend = strrchr (p, '/');
index 8fdaa96..577df8e 100644 (file)
@@ -280,7 +280,7 @@ Check the options for the component @var{component}.
 Update all configuration files with values taken from the global
 configuration file (usually @file{/etc/gnupg/gpgconf.conf}).
 
-@item --list-dirs
+@item --list-dirs [@var{names}]
 Lists the directories used by @command{gpgconf}.  One directory is
 listed per line, and each line consists of a colon-separated list where
 the first field names the directory type (for example @code{sysconfdir})
@@ -288,7 +288,9 @@ and the second field contains the percent-escaped directory.  Although
 they are not directories, the socket file names used by
 @command{gpg-agent} and @command{dirmngr} are printed as well.  Note
 that the socket file names and the @code{homedir} lines are the default
-names and they may be overridden by command line switches.
+names and they may be overridden by command line switches.  If
+@var{names} are given only the directories or file names specified by
+the list names are printed without any escaping.
 
 @item --list-config [@var{filename}]
 List the global configuration file in a colon separated format.  If
index 3de908c..9b76f19 100644 (file)
@@ -1,5 +1,5 @@
 /* yat2m.c - Yet Another Texi 2 Man converter
- *     Copyright (C) 2005, 2013, 2015 g10 Code GmbH
+ *     Copyright (C) 2005, 2013, 2015, 2016 g10 Code GmbH
  *      Copyright (C) 2006, 2008, 2011 Free Software Foundation, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 /*
 #include <time.h>
 
 
+#if __GNUC__
+# define MY_GCC_VERSION (__GNUC__ * 10000 \
+                         + __GNUC_MINOR__ * 100         \
+                         + __GNUC_PATCHLEVEL__)
+#else
+# define MY_GCC_VERSION 0
+#endif
+
+#if MY_GCC_VERSION >= 20500
+# define ATTR_PRINTF(f, a) __attribute__ ((format(printf,f,a)))
+# define ATTR_NR_PRINTF(f, a) __attribute__ ((noreturn, format(printf,f,a)))
+#else
+# define ATTR_PRINTF(f, a)
+# define ATTR_NR_PRINTF(f, a)
+#endif
+#if MY_GCC_VERSION >= 30200
+# define ATTR_MALLOC  __attribute__ ((__malloc__))
+#else
+# define ATTR_MALLOC
+#endif
+
+
+
 #define PGM "yat2m"
 #define VERSION "1.0"
 
@@ -214,8 +237,16 @@ static const char * const standard_sections[] =
 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
                               int *table_level, int *eol_action);
 
+static void die (const char *format, ...) ATTR_NR_PRINTF(1,2);
+static void err (const char *format, ...) ATTR_PRINTF(1,2);
+static void inf (const char *format, ...) ATTR_PRINTF(1,2);
+static void *xmalloc (size_t n) ATTR_MALLOC;
+static void *xcalloc (size_t n, size_t m) ATTR_MALLOC;
 
 
+
+/*-- Functions --*/
+
 /* Print diagnostic message and exit with failure. */
 static void
 die (const char *format, ...)
@@ -558,7 +589,7 @@ get_section_buffer (const char *name)
   for (i=0; i < thepage.n_sections; i++)
     if (!thepage.sections[i].name)
       break;
-  if (i < thepage.n_sections)
+  if (thepage.n_sections && i < thepage.n_sections)
     sect = thepage.sections + i;
   else
     {
@@ -715,7 +746,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
     { "subsection", 6, "\n.SS " },
     { "chapheading", 0},
     { "item",    2, ".TP\n.B " },
-    { "itemx",   2, ".TP\n.B " },
+    { "itemx",   2, ".TQ\n.B " },
     { "table",   3 },
     { "itemize",   3 },
     { "bullet",  0, "* " },
@@ -762,6 +793,8 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
             {
               if ((*table_level)-- > 1)
                 fputs (".RE\n", fp);
+              else
+                fputs (".P\n", fp);
             }
           else if (n >= 7 && !memcmp (s, "example", 7)
               && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
@@ -853,7 +886,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
         }
       else
         inf ("texinfo command '%s' not supported (%.*s)", command,
-             ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
+             (int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
     }
 
   if (*rest == '{')
@@ -965,7 +998,7 @@ proc_texi_buffer (FILE *fp, const char *line, size_t len,
       assert (n <= len);
       s += n; len -= n;
       s--; len++;
-      in_cmd = 0;
+      /* in_cmd = 0; -- doc only */
     }
 }
 
index fb74655..9e58520 100644 (file)
@@ -190,13 +190,18 @@ initialize(void)
     is_initialized=1;
 }
 
-/****************
- * Check whether this is an armored file or not See also
+
+/*
+ * Check whether this is an armored file.  See also
  * parse-packet.c for details on this code.
+ *
+ * Note that the buffer BUF needs to be at least 2 bytes long.  If in
+ * doubt that the second byte to 0.
+ *
  * Returns: True if it seems to be armored
  */
 static int
-is_armored( const byte *buf )
+is_armored (const byte *buf)
 {
   int ctb, pkttype;
   int indeterminate_length_allowed;
@@ -274,15 +279,17 @@ is_armored( const byte *buf )
 int
 use_armor_filter( IOBUF a )
 {
-    byte buf[1];
+    byte buf[2];
     int n;
 
     /* fixme: there might be a problem with iobuf_peek */
-    n = iobuf_peek(a, buf, 1 );
+    n = iobuf_peek (a, buf, 2);
     if( n == -1 )
        return 0; /* EOF, doesn't matter whether armored or not */
     if( !n )
        return 1; /* can't check it: try armored */
+    if (n != 2)
+       return 0; /* short buffer */
     return is_armored(buf);
 }
 
@@ -530,7 +537,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
     /* (the line is always a C string but maybe longer) */
     if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
        ;
-    else if( !is_armored( line ) ) {
+    else if (len >= 2 && !is_armored (line)) {
        afx->inp_checked = 1;
        afx->inp_bypass = 1;
        return 0;
@@ -1409,8 +1416,9 @@ unarmor_pump (UnarmorPump x, int c)
     switch (x->state) {
       case STA_init:
         {
-            byte tmp[1];
+            byte tmp[2];
             tmp[0] = c;
+            tmp[1] = 0;
             if ( is_armored (tmp) )
                 x->state = c == '-'? STA_first_dash : STA_wait_newline;
             else {
index 2745734..86d42ef 100644 (file)
@@ -635,6 +635,7 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
 
     write_header(out, ctb, calc_plaintext( pt ) );
     log_assert (pt->mode == 'b' || pt->mode == 't' || pt->mode == 'u'
+                || pt->mode == 'm'
                 || pt->mode == 'l' || pt->mode == '1');
     iobuf_put(out, pt->mode );
     iobuf_put(out, pt->namelen );
@@ -972,28 +973,49 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
        sig->unhashed = newarea;
 }
 
-/****************
+/*
  * Put all the required stuff from SIG into subpackets of sig.
+ * PKSK is the signing key.
  * Hmmm, should we delete those subpackets which are in a wrong area?
  */
 void
-build_sig_subpkt_from_sig( PKT_signature *sig )
+build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
 {
     u32  u;
-    byte buf[8];
+    byte buf[1+MAX_FINGERPRINT_LEN];
+    size_t fprlen;
 
-    u = sig->keyid[0];
-    buf[0] = (u >> 24) & 0xff;
-    buf[1] = (u >> 16) & 0xff;
-    buf[2] = (u >>  8) & 0xff;
-    buf[3] = u & 0xff;
-    u = sig->keyid[1];
-    buf[4] = (u >> 24) & 0xff;
-    buf[5] = (u >> 16) & 0xff;
-    buf[6] = (u >>  8) & 0xff;
-    buf[7] = u & 0xff;
-    build_sig_subpkt( sig, SIGSUBPKT_ISSUER, buf, 8 );
+    /* For v4 keys we need to write the ISSUER subpacket.  We do not
+     * want that for a future v5 format.  */
+    if (pksk->version < 5)
+      {
+        u = sig->keyid[0];
+        buf[0] = (u >> 24) & 0xff;
+        buf[1] = (u >> 16) & 0xff;
+        buf[2] = (u >>  8) & 0xff;
+        buf[3] = u & 0xff;
+        u = sig->keyid[1];
+        buf[4] = (u >> 24) & 0xff;
+        buf[5] = (u >> 16) & 0xff;
+        buf[6] = (u >>  8) & 0xff;
+        buf[7] = u & 0xff;
+        build_sig_subpkt (sig, SIGSUBPKT_ISSUER, buf, 8);
+      }
+
+    /* For a future v5 keys we write the ISSUER_FPR subpacket.  We
+     * also write that for a v4 key is experimental support for
+     * RFC4880bis is requested.  */
+    if (pksk->version > 4 || opt.flags.rfc4880bis)
+      {
+        fingerprint_from_pk (pksk, buf+1, &fprlen);
+        if (fprlen == 20)
+          {
+            buf[0] = pksk->version;
+            build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21);
+          }
+      }
 
+    /* Write the timestamp.  */
     u = sig->timestamp;
     buf[0] = (u >> 24) & 0xff;
     buf[1] = (u >> 16) & 0xff;
index be1a593..2cb44f9 100644 (file)
@@ -733,28 +733,18 @@ fetch_url (ctrl_t ctrl)
     log_error("error retrieving URL from card: %s\n",gpg_strerror(rc));
   else
     {
-      struct keyserver_spec *spec=NULL;
-
       rc=agent_scd_getattr("KEY-FPR",&info);
       if(rc)
        log_error("error retrieving key fingerprint from card: %s\n",
                  gpg_strerror(rc));
       else if (info.pubkey_url && *info.pubkey_url)
-       {
-         spec = parse_keyserver_uri (info.pubkey_url, 1);
-         if(spec && info.fpr1valid)
-           {
-             /* This is not perfectly right.  Currently, all card
-                fingerprints are 20 digits, but what about
-                fingerprints for a future v5 key?  We should get the
-                length from somewhere lower in the code.  In any
-                event, the fpr/keyid is not meaningful for straight
-                HTTP fetches, but using it allows the card to point
-                to HKP and LDAP servers as well. */
-             rc = keyserver_import_fprint (ctrl, info.fpr1, 20, spec);
-             free_keyserver_spec(spec);
-           }
-       }
+        {
+          strlist_t sl = NULL;
+
+          add_to_strlist (&sl, info.pubkey_url);
+          rc = keyserver_fetch (ctrl, sl);
+          free_strlist (sl);
+        }
       else if (info.fpr1valid)
        {
           rc = keyserver_import_fprint (ctrl, info.fpr1, 20, opt.keyserver);
index bdddef1..c34beec 100644 (file)
@@ -295,6 +295,10 @@ compress_filter( void *opaque, int control,
 static void
 release_context (compress_filter_context_t *ctx)
 {
+  xfree(ctx->inbuf);
+  ctx->inbuf = NULL;
+  xfree(ctx->outbuf);
+  ctx->outbuf = NULL;
   xfree (ctx);
 }
 
index 57d24be..54a17c3 100644 (file)
@@ -335,7 +335,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
     {
       /* Note that PT has been initialized above in !no_literal mode.  */
       pt->timestamp = make_timestamp();
-      pt->mode = opt.textmode? 't' : 'b';
+      pt->mode = opt.mimemode? 'm' : opt.textmode? 't' : 'b';
       pt->len = filesize;
       pt->new_ctb = !pt->len;
       pt->buf = inp;
@@ -674,7 +674,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
   if (!opt.no_literal)
     {
       pt->timestamp = make_timestamp();
-      pt->mode = opt.textmode ? 't' : 'b';
+      pt->mode = opt.mimemode? 'm' : opt.textmode ? 't' : 'b';
       pt->len = filesize;
       pt->new_ctb = !pt->len;
       pt->buf = inp;
index b067376..92235fb 100644 (file)
 #include "i18n.h"
 #include "membuf.h"
 #include "host2net.h"
+#include "zb32.h"
+#include "recsel.h"
+#include "mbox-util.h"
+#include "init.h"
 #include "trustdb.h"
 #include "call-agent.h"
 
@@ -56,6 +60,16 @@ struct export_stats_s
 };
 
 
+/* A global variable to store the selector created from
+ * --export-filter keep-uid=EXPR.
+ *
+ * FIXME: We should put this into the CTRL object but that requires a
+ * lot more changes right now.
+ */
+static recsel_expr_t export_keep_uid;
+
+
+
 /* Local prototypes.  */
 static int do_export (ctrl_t ctrl, strlist_t users, int secret,
                       unsigned int options, export_stats_t stats);
@@ -63,8 +77,18 @@ static int do_export_stream (ctrl_t ctrl, iobuf_t out,
                              strlist_t users, int secret,
                              kbnode_t *keyblock_out, unsigned int options,
                             export_stats_t stats, int *any);
+static gpg_error_t print_pka_or_dane_records
+/**/                 (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk,
+                      const void *data, size_t datalen,
+                      int print_pka, int print_dane);
 
 \f
+static void
+cleanup_export_globals (void)
+{
+  recsel_release (export_keep_uid);
+  export_keep_uid = NULL;
+}
 
 
 /* Option parser for export options.  See parse_options fro
@@ -84,6 +108,10 @@ parse_export_options(char *str,unsigned int *options,int noisy)
        N_("remove unusable parts from key during export")},
       {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL,
        N_("remove as much as possible from key during export")},
+
+      {"export-pka", EXPORT_PKA_FORMAT, NULL, NULL },
+      {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL },
+
       /* Aliases for backward compatibility */
       {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
       {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL},
@@ -100,6 +128,38 @@ parse_export_options(char *str,unsigned int *options,int noisy)
 }
 
 
+/* Parse and set an export filter from string.  STRING has the format
+ * "NAME=EXPR" with NAME being the name of the filter.  Spaces before
+ * and after NAME are not allowed.  If this function is called several
+ * times all expressions for the same NAME are concatenated.
+ * Supported filter names are:
+ *
+ *  - keep-uid :: If the expression evaluates to true for a certain
+ *                user ID packet, that packet and all it dependencies
+ *                will be exported.  The expression may use these
+ *                variables:
+ *
+ *                - uid  :: The entire user ID.
+ *                - mbox :: The mail box part of the user ID.
+ *                - primary :: Evaluate to true for the primary user ID.
+ */
+gpg_error_t
+parse_and_set_export_filter (const char *string)
+{
+  gpg_error_t err;
+
+  /* Auto register the cleanup function.  */
+  register_mem_cleanup_func (cleanup_export_globals);
+
+  if (!strncmp (string, "keep-uid=", 9))
+    err = recsel_parse_expr (&export_keep_uid, string+9);
+  else
+    err = gpg_error (GPG_ERR_INV_NAME);
+
+  return err;
+}
+
+
 /* Create a new export stats object initialized to zero.  On error
    returns NULL and sets ERRNO.  */
 export_stats_t
@@ -265,7 +325,7 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options,
   if (rc)
     return rc;
 
-  if ( opt.armor )
+  if ( opt.armor && !(options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)) )
     {
       afx = new_armor_context ();
       afx->what = secret? 5 : 1;
@@ -1147,8 +1207,567 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
 }
 
 
+/* Write KEYBLOCK either to stdout or to the file set with the
+ * --output option.  This is a simplified version of do_export_stream
+ * which supports only a few export options.  */
+gpg_error_t
+write_keyblock_to_output (kbnode_t keyblock, int with_armor,
+                          unsigned int options)
+{
+  gpg_error_t err;
+  const char *fname;
+  iobuf_t out;
+  kbnode_t node;
+  armor_filter_context_t *afx = NULL;
+  iobuf_t out_help = NULL;
+  PKT_public_key *pk = NULL;
+
+  fname = opt.outfile? opt.outfile : "-";
+  if (is_secured_filename (fname) )
+    return gpg_error (GPG_ERR_EPERM);
+
+  out = iobuf_create (fname, 0);
+  if (!out)
+    {
+      err = gpg_error_from_syserror ();
+      log_error(_("can't create '%s': %s\n"), fname, gpg_strerror (err));
+      return err;
+    }
+  if (opt.verbose)
+    log_info (_("writing to '%s'\n"), iobuf_get_fname_nonnull (out));
+
+  if ((options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)))
+    {
+      with_armor = 0;
+      out_help = iobuf_temp ();
+    }
+
+  if (with_armor)
+    {
+      afx = new_armor_context ();
+      afx->what = 1;
+      push_armor_filter (afx, out);
+    }
+
+  for (node = keyblock; node; node = node->next)
+    {
+      if (is_deleted_kbnode (node) || node->pkt->pkttype == PKT_RING_TRUST)
+        continue;
+      if (!pk && (node->pkt->pkttype == PKT_PUBLIC_KEY
+                  || node->pkt->pkttype == PKT_SECRET_KEY))
+        pk = node->pkt->pkt.public_key;
+
+      err = build_packet (out_help? out_help : out, node->pkt);
+      if (err)
+        {
+          log_error ("build_packet(%d) failed: %s\n",
+                     node->pkt->pkttype, gpg_strerror (err) );
+          goto leave;
+        }
+    }
+  err = 0;
+
+  if (out_help && pk)
+    {
+      const void *data;
+      size_t datalen;
+
+      iobuf_flush_temp (out_help);
+      data = iobuf_get_temp_buffer (out_help);
+      datalen = iobuf_get_temp_length (out_help);
+
+      err = print_pka_or_dane_records (out,
+                                       keyblock, pk, data, datalen,
+                                       (options & EXPORT_PKA_FORMAT),
+                                       (options & EXPORT_DANE_FORMAT));
+    }
+
+ leave:
+  if (err)
+    iobuf_cancel (out);
+  else
+    iobuf_close (out);
+  iobuf_cancel (out_help);
+  release_armor_context (afx);
+  return err;
+}
+
+
+/* Helper for apply_keep_uid_filter.  */
+static const char *
+filter_getval (void *cookie, const char *propname)
+{
+  kbnode_t node = cookie;
+  const char *result;
+
+  if (node->pkt->pkttype == PKT_USER_ID)
+    {
+      if (!strcmp (propname, "uid"))
+        result = node->pkt->pkt.user_id->name;
+      else if (!strcmp (propname, "mbox"))
+        {
+          if (!node->pkt->pkt.user_id->mbox)
+            {
+              node->pkt->pkt.user_id->mbox
+                = mailbox_from_userid (node->pkt->pkt.user_id->name);
+            }
+          return node->pkt->pkt.user_id->mbox;
+        }
+      else if (!strcmp (propname, "primary"))
+        result = node->pkt->pkt.user_id->is_primary? "1":"0";
+      else
+        result = NULL;
+    }
+  else
+    result = NULL;
+
+  return result;
+}
+
+/*
+ * Apply the keep-uid filter to the keyblock.  The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+  kbnode_t node;
+
+  for (node = keyblock->next; node; node = node->next )
+    {
+      if (node->pkt->pkttype == PKT_USER_ID)
+        {
+          if (!recsel_select (selector, filter_getval, node))
+            {
+              /* log_debug ("keep-uid: deleting '%s'\n", */
+              /*            node->pkt->pkt.user_id->name); */
+              /* The UID packet and all following packets up to the
+               * next UID or a subkey.  */
+              delete_kbnode (node);
+              for (; node->next
+                     && node->next->pkt->pkttype != PKT_USER_ID
+                     && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
+                     && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
+                   node = node->next)
+                delete_kbnode (node->next);
+           }
+          /* else */
+          /*   log_debug ("keep-uid: keeping '%s'\n", */
+          /*              node->pkt->pkt.user_id->name); */
+        }
+    }
+}
+
+
+/* Print DANE or PKA records for all user IDs in KEYBLOCK to OUT.  The
+ * data for the record is taken from (DATA,DATELEN).  PK is the public
+ * key packet with the primary key. */
+static gpg_error_t
+print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk,
+                           const void *data, size_t datalen,
+                           int print_pka, int print_dane)
+{
+  gpg_error_t err = 0;
+  kbnode_t kbctx, node;
+  PKT_user_id *uid;
+  char *mbox = NULL;
+  char hashbuf[32];
+  char *hash = NULL;
+  char *domain;
+  const char *s;
+  unsigned int len;
+  estream_t fp = NULL;
+  char *hexdata = NULL;
+  char *hexfpr;
+
+  hexfpr = hexfingerprint (pk, NULL, 0);
+  hexdata = bin2hex (data, datalen, NULL);
+  if (!hexdata)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  ascii_strlwr (hexdata);
+  fp = es_fopenmem (0, "rw,samethread");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
+    {
+      if (node->pkt->pkttype != PKT_USER_ID)
+        continue;
+      uid = node->pkt->pkt.user_id;
+
+      if (uid->is_expired || uid->is_revoked)
+        continue;
+
+      xfree (mbox);
+      mbox = mailbox_from_userid (uid->name);
+      if (!mbox)
+        continue;
+
+      domain = strchr (mbox, '@');
+      *domain++ = 0;
+
+      if (print_pka)
+        {
+          es_fprintf (fp, "$ORIGIN _pka.%s.\n; %s\n; ", domain, hexfpr);
+          print_utf8_buffer (fp, uid->name, uid->len);
+          es_putc ('\n', fp);
+          gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
+          xfree (hash);
+          hash = zb32_encode (hashbuf, 8*20);
+          if (!hash)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          len = strlen (hexfpr)/2;
+          es_fprintf (fp, "%s TYPE37 \\# %u 0006 0000 00 %02X %s\n\n",
+                      hash, 6 + len, len, hexfpr);
+        }
+
+      if (print_dane && hexdata)
+        {
+          es_fprintf (fp, "$ORIGIN _openpgpkey.%s.\n; %s\n; ", domain, hexfpr);
+          print_utf8_buffer (fp, uid->name, uid->len);
+          es_putc ('\n', fp);
+          gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox));
+          xfree (hash);
+          hash = bin2hex (hashbuf, 28, NULL);
+          if (!hash)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          ascii_strlwr (hash);
+          len = strlen (hexdata)/2;
+          es_fprintf (fp, "%s TYPE61 \\# %u (\n", hash, len);
+          for (s = hexdata; ;)
+            {
+              es_fprintf (fp, "\t%.64s\n", s);
+              if (strlen (s) < 64)
+                break;
+              s += 64;
+            }
+          es_fputs ("\t)\n\n", fp);
+        }
+    }
+
+  /* Make sure it is a string and write it.  */
+  es_fputc (0, fp);
+  {
+    void *vp;
+
+    if (es_fclose_snatch (fp, &vp, NULL))
+      {
+        err = gpg_error_from_syserror ();
+        goto leave;
+      }
+    fp = NULL;
+    iobuf_writestr (out, vp);
+    es_free (vp);
+  }
+  err = 0;
+
+ leave:
+  xfree (hash);
+  xfree (mbox);
+  es_fclose (fp);
+  xfree (hexdata);
+  xfree (hexfpr);
+  return err;
+}
+
+
+/* Helper for do_export_stream which writes one keyblock to OUT.  */
+static gpg_error_t
+do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
+                        iobuf_t out, int secret, unsigned int options,
+                        export_stats_t stats, int *any,
+                        KEYDB_SEARCH_DESC *desc, size_t ndesc,
+                        size_t descindex, gcry_cipher_hd_t cipherhd)
+{
+  gpg_error_t err;
+  char *cache_nonce = NULL;
+  subkey_list_t subkey_list = NULL;  /* Track already processed subkeys. */
+  int skip_until_subkey = 0;
+  int cleartext = 0;
+  char *hexgrip = NULL;
+  char *serialno = NULL;
+  PKT_public_key *pk;
+  u32 subkidbuf[2], *subkid;
+  kbnode_t kbctx, node;
+
+  for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+    {
+      if (skip_until_subkey)
+        {
+          if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+            skip_until_subkey = 0;
+          else
+            continue;
+        }
+
+      /* We used to use comment packets, but not any longer.  In
+       * case we still have comments on a key, strip them here
+       * before we call build_packet(). */
+      if (node->pkt->pkttype == PKT_COMMENT)
+        continue;
+
+      /* Make sure that ring_trust packets never get exported. */
+      if (node->pkt->pkttype == PKT_RING_TRUST)
+        continue;
+
+      /* If exact is set, then we only export what was requested
+       * (plus the primary key, if the user didn't specifically
+       * request it). */
+      if (desc[descindex].exact && node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        {
+          if (!exact_subkey_match_p (desc+descindex, node))
+            {
+              /* Before skipping this subkey, check whether any
+               * other description wants an exact match on a
+               * subkey and include that subkey into the output
+               * too.  Need to add this subkey to a list so that
+               * it won't get processed a second time.
+               *
+               * So the first step here is to check that list and
+               * skip in any case if the key is in that list.
+               *
+               * We need this whole mess because the import
+               * function of GnuPG < 2.1 is not able to merge
+               * secret keys and thus it is useless to output them
+               * as two separate keys and have import merge them.
+               */
+              if (subkey_in_list_p (subkey_list, node))
+                skip_until_subkey = 1; /* Already processed this one. */
+              else
+                {
+                  size_t j;
+
+                  for (j=0; j < ndesc; j++)
+                    if (j != descindex && desc[j].exact
+                        && exact_subkey_match_p (desc+j, node))
+                      break;
+                  if (!(j < ndesc))
+                    skip_until_subkey = 1; /* No other one matching. */
+                }
+            }
+
+          if (skip_until_subkey)
+            continue;
+
+          /* Mark this one as processed. */
+          {
+            subkey_list_t tmp = new_subkey_list_item (node);
+            tmp->next = subkey_list;
+            subkey_list = tmp;
+          }
+        }
+
+      if (node->pkt->pkttype == PKT_SIGNATURE)
+        {
+          /* Do not export packets which are marked as not
+           * exportable.  */
+          if (!(options & EXPORT_LOCAL_SIGS)
+              && !node->pkt->pkt.signature->flags.exportable)
+            continue; /* not exportable */
+
+          /* Do not export packets with a "sensitive" revocation key
+           * unless the user wants us to.  Note that we do export
+           * these when issuing the actual revocation (see revoke.c). */
+          if (!(options & EXPORT_SENSITIVE_REVKEYS)
+              && node->pkt->pkt.signature->revkey)
+            {
+              int i;
+
+              for (i = 0; i < node->pkt->pkt.signature->numrevkeys; i++)
+                if ((node->pkt->pkt.signature->revkey[i].class & 0x40))
+                  break;
+              if (i < node->pkt->pkt.signature->numrevkeys)
+                continue;
+            }
+        }
+
+      /* Don't export attribs? */
+      if (!(options & EXPORT_ATTRIBUTES)
+          && node->pkt->pkttype == PKT_USER_ID
+          && node->pkt->pkt.user_id->attrib_data)
+        {
+          /* Skip until we get to something that is not an attrib or a
+           * signature on an attrib.  */
+          while (kbctx->next && kbctx->next->pkt->pkttype == PKT_SIGNATURE)
+            kbctx = kbctx->next;
+
+          continue;
+        }
+
+      if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY
+                     || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+        {
+          pk = node->pkt->pkt.public_key;
+          if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+            subkid = NULL;
+          else
+            {
+              keyid_from_pk (pk, subkidbuf);
+              subkid = subkidbuf;
+            }
+
+          if (pk->seckey_info)
+            {
+              log_error ("key %s: oops: seckey_info already set"
+                         " - skipped\n", keystr_with_sub (keyid, subkid));
+              skip_until_subkey = 1;
+              continue;
+            }
+
+          xfree (hexgrip);
+          err = hexkeygrip_from_pk (pk, &hexgrip);
+          if (err)
+            {
+              log_error ("key %s: error computing keygrip: %s"
+                         " - skipped\n", keystr_with_sub (keyid, subkid),
+                         gpg_strerror (err));
+              skip_until_subkey = 1;
+              err = 0;
+              continue;
+            }
+
+          xfree (serialno);
+          serialno = NULL;
+          if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
+            {
+              /* We are asked not to export the secret parts of the
+               * primary key.  Make up an error code to create the
+               * stub.  */
+              err = GPG_ERR_NOT_FOUND;
+            }
+          else
+            err = agent_get_keyinfo (ctrl, hexgrip, &serialno, &cleartext);
+
+          if ((!err && serialno)
+              && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
+            {
+              /* It does not make sense to export a key with its
+               * primary key on card using a non-key stub.  Thus we
+               * skip those keys when used with --export-secret-subkeys. */
+              log_info (_("key %s: key material on-card - skipped\n"),
+                        keystr_with_sub (keyid, subkid));
+              skip_until_subkey = 1;
+            }
+          else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
+                   || (!err && serialno))
+            {
+              /* Create a key stub.  */
+              struct seckey_info *ski;
+              const char *s;
+
+              pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
+              if (!ski)
+                {
+                  err = gpg_error_from_syserror ();
+                  goto leave;
+                }
+
+              ski->is_protected = 1;
+              if (err)
+                ski->s2k.mode = 1001; /* GNU dummy (no secret key).  */
+              else
+                {
+                  ski->s2k.mode = 1002; /* GNU-divert-to-card.  */
+                  for (s=serialno; sizeof (ski->ivlen) && *s && s[1];
+                       ski->ivlen++, s += 2)
+                    ski->iv[ski->ivlen] = xtoi_2 (s);
+                }
+
+              err = build_packet (out, node->pkt);
+              if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+                {
+                  stats->exported++;
+                  print_status_exported (node->pkt->pkt.public_key);
+                }
+            }
+          else if (!err)
+            {
+              err = receive_seckey_from_agent (ctrl, cipherhd,
+                                               cleartext, &cache_nonce,
+                                               hexgrip, pk);
+              if (err)
+                {
+                  if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
+                    goto leave;
+                  skip_until_subkey = 1;
+                  err = 0;
+                }
+              else
+                {
+                  err = build_packet (out, node->pkt);
+                  if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+                    {
+                      stats->exported++;
+                      print_status_exported (node->pkt->pkt.public_key);
+                    }
+                }
+            }
+          else
+            {
+              log_error ("key %s: error getting keyinfo from agent: %s"
+                         " - skipped\n", keystr_with_sub (keyid, subkid),
+                             gpg_strerror (err));
+              skip_until_subkey = 1;
+              err = 0;
+            }
+
+          xfree (pk->seckey_info);
+          pk->seckey_info = NULL;
+          {
+            int i;
+            for (i = pubkey_get_npkey (pk->pubkey_algo);
+                 i < pubkey_get_nskey (pk->pubkey_algo); i++)
+              {
+                gcry_mpi_release (pk->pkey[i]);
+                pk->pkey[i] = NULL;
+              }
+          }
+        }
+      else /* Not secret or common packets.  */
+        {
+          err = build_packet (out, node->pkt);
+          if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+            {
+              stats->exported++;
+              print_status_exported (node->pkt->pkt.public_key);
+            }
+        }
+
+      if (err)
+        {
+          log_error ("build_packet(%d) failed: %s\n",
+                     node->pkt->pkttype, gpg_strerror (err));
+          goto leave;
+        }
+
+      if (!skip_until_subkey)
+        *any = 1;
+    }
+
+ leave:
+  release_subkey_list (subkey_list);
+  xfree (serialno);
+  xfree (hexgrip);
+  xfree (cache_nonce);
+  return err;
+}
+
+
 /* Export the keys identified by the list of strings in USERS to the
-   stream OUT.  If Secret is false public keys will be exported.  With
+   stream OUT.  If SECRET is false public keys will be exported.  With
    secret true secret keys will be exported; in this case 1 means the
    entire secret keyblock and 2 only the subkeys.  OPTIONS are the
    export options to apply.  If KEYBLOCK_OUT is not NULL, AND the exit
@@ -1163,17 +1782,15 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
 {
   gpg_error_t err = 0;
   PACKET pkt;
-  KBNODE keyblock = NULL;
-  KBNODE kbctx, node;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
   size_t ndesc, descindex;
   KEYDB_SEARCH_DESC *desc = NULL;
-  subkey_list_t subkey_list = NULL;  /* Track already processed subkeys. */
   KEYDB_HANDLE kdbhd;
   strlist_t sl;
   gcry_cipher_hd_t cipherhd = NULL;
-  char *cache_nonce = NULL;
   struct export_stats_s dummystats;
-  int cleartext = 0;
+  iobuf_t out_help = NULL;
 
   if (!stats)
     stats = &dummystats;
@@ -1183,10 +1800,14 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   if (!kdbhd)
     return gpg_error_from_syserror ();
 
-  /* For the DANE format override the options.  */
-  if ((options & EXPORT_DANE_FORMAT))
-    options = (EXPORT_DANE_FORMAT | EXPORT_MINIMAL | EXPORT_CLEAN);
-
+  /* For the PKA and DANE format open a helper iobuf and for DANE
+   * enforce some options.  */
+  if ((options & (EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT)))
+    {
+      out_help = iobuf_temp ();
+      if ((options & EXPORT_DANE_FORMAT))
+        options |= EXPORT_MINIMAL | EXPORT_CLEAN;
+    }
 
   if (!users)
     {
@@ -1258,7 +1879,6 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
 
   for (;;)
     {
-      int skip_until_subkey = 0;
       u32 keyid[2];
       PKT_public_key *pk;
 
@@ -1326,278 +1946,60 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
       if ((options & EXPORT_CLEAN))
         clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL);
 
-      /* And write it. */
-      xfree (cache_nonce);
-      cache_nonce = NULL;
-      for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+      if (export_keep_uid)
         {
-          if (skip_until_subkey)
-            {
-              if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-                skip_until_subkey = 0;
-              else
-                continue;
-            }
-
-          /* We used to use comment packets, but not any longer.  In
-             case we still have comments on a key, strip them here
-             before we call build_packet(). */
-          if (node->pkt->pkttype == PKT_COMMENT)
-            continue;
-
-          /* Make sure that ring_trust packets never get exported. */
-          if (node->pkt->pkttype == PKT_RING_TRUST)
-            continue;
-
-          /* If exact is set, then we only export what was requested
-             (plus the primary key, if the user didn't specifically
-             request it). */
-          if (desc[descindex].exact
-              && node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-            {
-              if (!exact_subkey_match_p (desc+descindex, node))
-                {
-                  /* Before skipping this subkey, check whether any
-                     other description wants an exact match on a
-                     subkey and include that subkey into the output
-                     too.  Need to add this subkey to a list so that
-                     it won't get processed a second time.
-
-                     So the first step here is to check that list and
-                     skip in any case if the key is in that list.
-
-                     We need this whole mess because the import
-                     function of GnuPG < 2.1 is not able to merge
-                     secret keys and thus it is useless to output them
-                     as two separate keys and have import merge them.  */
-                  if (subkey_in_list_p (subkey_list, node))
-                    skip_until_subkey = 1; /* Already processed this one. */
-                  else
-                    {
-                      size_t j;
-
-                      for (j=0; j < ndesc; j++)
-                        if (j != descindex && desc[j].exact
-                            && exact_subkey_match_p (desc+j, node))
-                          break;
-                      if (!(j < ndesc))
-                        skip_until_subkey = 1; /* No other one matching. */
-                    }
-                }
-
-              if(skip_until_subkey)
-                continue;
-
-              /* Mark this one as processed. */
-              {
-                subkey_list_t tmp = new_subkey_list_item (node);
-                tmp->next = subkey_list;
-                subkey_list = tmp;
-              }
-            }
-
-          if (node->pkt->pkttype == PKT_SIGNATURE)
-            {
-              /* Do not export packets which are marked as not
-                 exportable.  */
-              if (!(options&EXPORT_LOCAL_SIGS)
-                  && !node->pkt->pkt.signature->flags.exportable)
-                continue; /* not exportable */
-
-              /* Do not export packets with a "sensitive" revocation
-                 key unless the user wants us to.  Note that we do
-                 export these when issuing the actual revocation
-                 (see revoke.c). */
-              if (!(options&EXPORT_SENSITIVE_REVKEYS)
-                  && node->pkt->pkt.signature->revkey)
-                {
-                  int i;
-
-                  for (i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
-                    if ( (node->pkt->pkt.signature->revkey[i].class & 0x40))
-                      break;
-
-                  if (i < node->pkt->pkt.signature->numrevkeys)
-                    continue;
-                }
-            }
-
-          /* Don't export attribs? */
-          if (!(options&EXPORT_ATTRIBUTES)
-              && node->pkt->pkttype == PKT_USER_ID
-              && node->pkt->pkt.user_id->attrib_data )
-            {
-             /* Skip until we get to something that is not an attrib
-                or a signature on an attrib */
-             while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE)
-                kbctx = kbctx->next;
-
-             continue;
-           }
-
-          if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY
-                         || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
-            {
-              u32 subkidbuf[2], *subkid;
-              char *hexgrip, *serialno;
-
-              pk = node->pkt->pkt.public_key;
-              if (node->pkt->pkttype == PKT_PUBLIC_KEY)
-                subkid = NULL;
-              else
-                {
-                  keyid_from_pk (pk, subkidbuf);
-                  subkid = subkidbuf;
-                }
-
-              if (pk->seckey_info)
-                {
-                  log_error ("key %s: oops: seckey_info already set"
-                             " - skipped\n", keystr_with_sub (keyid, subkid));
-                  skip_until_subkey = 1;
-                  continue;
-                }
-
-              err = hexkeygrip_from_pk (pk, &hexgrip);
-              if (err)
-                {
-                  log_error ("key %s: error computing keygrip: %s"
-                             " - skipped\n", keystr_with_sub (keyid, subkid),
-                             gpg_strerror (err));
-                  skip_until_subkey = 1;
-                  err = 0;
-                  continue;
-                }
-
-              if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
-                {
-                  /* We are asked not to export the secret parts of
-                     the primary key.  Make up an error code to create
-                     the stub.  */
-                  err = GPG_ERR_NOT_FOUND;
-                  serialno = NULL;
-                }
-              else
-                err = agent_get_keyinfo (ctrl, hexgrip, &serialno, &cleartext);
-
-              if ((!err && serialno)
-                  && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
-                {
-                  /* It does not make sense to export a key with its
-                     primary key on card using a non-key stub.  Thus
-                     we skip those keys when used with
-                     --export-secret-subkeys. */
-                  log_info (_("key %s: key material on-card - skipped\n"),
-                            keystr_with_sub (keyid, subkid));
-                  skip_until_subkey = 1;
-                }
-              else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-                       || (!err && serialno))
-                {
-                  /* Create a key stub.  */
-                  struct seckey_info *ski;
-                  const char *s;
-
-                  pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
-                  if (!ski)
-                    {
-                      err = gpg_error_from_syserror ();
-                      xfree (hexgrip);
-                      goto leave;
-                    }
-
-                  ski->is_protected = 1;
-                  if (err)
-                    ski->s2k.mode = 1001; /* GNU dummy (no secret key).  */
-                  else
-                    {
-                      ski->s2k.mode = 1002; /* GNU-divert-to-card.  */
-                      for (s=serialno; sizeof (ski->ivlen) && *s && s[1];
-                           ski->ivlen++, s += 2)
-                        ski->iv[ski->ivlen] = xtoi_2 (s);
-                    }
-
-                  err = build_packet (out, node->pkt);
-                  if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
-                    {
-                      stats->exported++;
-                      print_status_exported (node->pkt->pkt.public_key);
-                    }
-                }
-              else if (!err)
-                {
-                  err = receive_seckey_from_agent (ctrl, cipherhd,
-                                                   cleartext, &cache_nonce,
-                                                   hexgrip, pk);
-                  if (err)
-                    {
-                      if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
-                        goto leave;
-                      skip_until_subkey = 1;
-                      err = 0;
-                    }
-                  else
-                    {
-                      err = build_packet (out, node->pkt);
-                      if (node->pkt->pkttype == PKT_PUBLIC_KEY)
-                        {
-                          stats->exported++;
-                          print_status_exported (node->pkt->pkt.public_key);
-                        }
-                    }
-                }
-              else
-                {
-                  log_error ("key %s: error getting keyinfo from agent: %s"
-                             " - skipped\n", keystr_with_sub (keyid, subkid),
-                             gpg_strerror (err));
-                  skip_until_subkey = 1;
-                  err = 0;
-                }
-
-              xfree (pk->seckey_info);
-              pk->seckey_info = NULL;
-              xfree (hexgrip);
-            }
-          else
-            {
-              err = build_packet (out, node->pkt);
-              if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
-                {
-                  stats->exported++;
-                  print_status_exported (node->pkt->pkt.public_key);
-                }
-            }
-
-
-          if (err)
-            {
-              log_error ("build_packet(%d) failed: %s\n",
-                         node->pkt->pkttype, gpg_strerror (err));
-              goto leave;
-           }
+          commit_kbnode (&keyblock);
+          apply_keep_uid_filter (keyblock, export_keep_uid);
+          commit_kbnode (&keyblock);
+        }
 
-          if (!skip_until_subkey)
-            *any = 1;
-       }
+      /* And write it. */
+      err = do_export_one_keyblock (ctrl, keyblock, keyid,
+                                    out_help? out_help : out,
+                                    secret, options, stats, any,
+                                    desc, ndesc, descindex, cipherhd);
+      if (err)
+        break;
 
       if (keyblock_out)
         {
           *keyblock_out = keyblock;
           break;
         }
+
+      if (out_help)
+        {
+          /* We want to write PKA or DANE records.  OUT_HELP has the
+           * keyblock and we print a record for each uid to OUT. */
+          const void *data;
+          size_t datalen;
+
+          iobuf_flush_temp (out_help);
+          data = iobuf_get_temp_buffer (out_help);
+          datalen = iobuf_get_temp_length (out_help);
+
+          err = print_pka_or_dane_records (out,
+                                           keyblock, pk, data, datalen,
+                                           (options & EXPORT_PKA_FORMAT),
+                                           (options & EXPORT_DANE_FORMAT));
+          if (err)
+            goto leave;
+
+          iobuf_close (out_help);
+          out_help = iobuf_temp ();
+        }
+
     }
   if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
     err = 0;
 
  leave:
+  iobuf_cancel (out_help);
   gcry_cipher_close (cipherhd);
-  release_subkey_list (subkey_list);
   xfree(desc);
   keydb_release (kdbhd);
   if (err || !keyblock_out)
     release_kbnode( keyblock );
-  xfree (cache_nonce);
   if( !*any )
     log_info(_("WARNING: nothing exported\n"));
   return err;
index 3883f87..516e9a1 100644 (file)
@@ -311,6 +311,7 @@ free_user_id (PKT_user_id *uid)
     free_attributes(uid);
     xfree (uid->prefs);
     xfree (uid->namehash);
+    xfree (uid->mbox);
     xfree (uid);
 }
 
index ad0148e..3fe8274 100644 (file)
@@ -1,7 +1,7 @@
 /* getkey.c -  Get a key from the database
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
  *               2007, 2008, 2010  Free Software Foundation, Inc.
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -143,6 +143,11 @@ static void merge_selfsigs (kbnode_t keyblock);
 static int lookup (getkey_ctx_t ctx,
                   kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
                   int want_secret);
+static kbnode_t finish_lookup (kbnode_t keyblock,
+                               unsigned int req_usage, int want_exact,
+                               unsigned int *r_flags);
+static void print_status_key_considered (kbnode_t keyblock, unsigned int flags);
+
 
 #if 0
 static void
@@ -659,12 +664,9 @@ get_pubkeys (ctrl_t ctrl,
 
 
 static void
-pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
-              KBNODE found_key)
+pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
 {
-  KBNODE a = found_key ? found_key : keyblock;
-
-  (void) ctx;
+  kbnode_t a = found_key ? found_key : keyblock;
 
   log_assert (a->pkt->pkttype == PKT_PUBLIC_KEY
               || a->pkt->pkttype == PKT_PUBLIC_SUBKEY);
@@ -749,7 +751,7 @@ get_pubkey (PKT_public_key * pk, u32 * keyid)
     rc = lookup (&ctx, &kb, &found_key, 0);
     if (!rc)
       {
-       pk_from_block (&ctx, pk, kb, found_key);
+       pk_from_block (pk, kb, found_key);
       }
     getkey_end (&ctx);
     release_kbnode (kb);
@@ -912,7 +914,7 @@ get_seckey (PKT_public_key *pk, u32 *keyid)
   err = lookup (&ctx, &keyblock, &found_key, 1);
   if (!err)
     {
-      pk_from_block (&ctx, pk, keyblock, found_key);
+      pk_from_block (pk, keyblock, found_key);
     }
   getkey_end (&ctx);
   release_kbnode (keyblock);
@@ -1118,7 +1120,7 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
   rc = lookup (ctx, ret_kb, &found_key, want_secret);
   if (!rc && pk)
     {
-      pk_from_block (ctx, pk, *ret_kb, found_key);
+      pk_from_block (pk, *ret_kb, found_key);
     }
 
   release_kbnode (help_kb);
@@ -1457,6 +1459,53 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
 }
 
 
+/* Get a public key from a file.
+ *
+ * PK is the buffer to store the key.  The caller needs to make sure
+ * that PK->REQ_USAGE is valid.  PK->REQ_USAGE is passed through to
+ * the lookup function and is a mask of PUBKEY_USAGE_SIG,
+ * PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT.  If this is non-zero, only
+ * keys with the specified usage will be returned.
+ *
+ * FNAME is the file name.  That file should contain exactly one
+ * keyblock.
+ *
+ * This function returns 0 on success.  Otherwise, an error code is
+ * returned.  In particular, GPG_ERR_NO_PUBKEY is returned if the key
+ * is not found.
+ *
+ * The self-signed data has already been merged into the public key
+ * using merge_selfsigs.  The caller must release the content of PK by
+ * calling release_public_key_parts (or, if PK was malloced, using
+ * free_public_key).
+ */
+gpg_error_t
+get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
+{
+  gpg_error_t err;
+  kbnode_t keyblock;
+  kbnode_t found_key;
+  unsigned int infoflags;
+
+  err = read_key_from_file (ctrl, fname, &keyblock);
+  if (!err)
+    {
+      /* Warning: node flag bits 0 and 1 should be preserved by
+       * merge_selfsigs.  FIXME: Check whether this still holds. */
+      merge_selfsigs (keyblock);
+      found_key = finish_lookup (keyblock, pk->req_usage, 0, &infoflags);
+      print_status_key_considered (keyblock, infoflags);
+      if (found_key)
+        pk_from_block (pk, keyblock, found_key);
+      else
+        err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+    }
+
+  release_kbnode (keyblock);
+  return err;
+}
+
+
 /* Lookup a key with the specified fingerprint.
  *
  * If PK is not NULL, the public key of the first result is returned
@@ -1513,7 +1562,7 @@ get_pubkey_byfprint (PKT_public_key *pk, kbnode_t *r_keyblock,
       memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
       rc = lookup (&ctx, &kb, &found_key, 0);
       if (!rc && pk)
-       pk_from_block (&ctx, pk, kb, found_key);
+       pk_from_block (pk, kb, found_key);
       if (!rc && r_keyblock)
        {
          *r_keyblock = kb;
@@ -1903,7 +1952,7 @@ getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
 
   rc = lookup (ctx, ret_keyblock, &found_key, ctx->want_secret);
   if (!rc && pk && ret_keyblock)
-    pk_from_block (ctx, pk, *ret_keyblock, found_key);
+    pk_from_block (pk, *ret_keyblock, found_key);
 
   return rc;
 }
@@ -3053,31 +3102,33 @@ merge_selfsigs (KBNODE keyblock)
 
 \f
 /* See whether the key satisfies any additional requirements specified
- * in CTX.  If so, return 1 and set CTX->FOUND_KEY to an appropriate
- * key or subkey.  Otherwise, return 0 if there was no appropriate
- * key.
+ * in CTX.  If so, return the node of an appropriate key or subkey.
+ * Otherwise, return NULL if there was no appropriate key.
  *
  * In case the primary key is not required, select a suitable subkey.
- * We need the primary key if PUBKEY_USAGE_CERT is set in
- * CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
- * is set in CTX->REQ_USAGE.
+ * We need the primary key if PUBKEY_USAGE_CERT is set in REQ_USAGE or
+ * we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG is set in
+ * REQ_USAGE.
  *
  * If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
- * are set in CTX->REQ_USAGE, we filter by the key's function.
- * Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
- * we only return a key if it is (at least) either a signing or a
+ * are set in REQ_USAGE, we filter by the key's function.  Concretely,
+ * if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then we only
+ * return a key if it is (at least) either a signing or a
  * certification key.
  *
- * If CTX->REQ_USAGE is set, then we reject any keys that are not good
+ * If REQ_USAGE is set, then we reject any keys that are not good
  * (i.e., valid, not revoked, not expired, etc.).  This allows the
  * getkey functions to be used for plain key listings.
  *
  * Sets the matched key's user id field (pk->user_id) to the user id
- * that matched the low-level search criteria or NULL.  If R_FLAGS is
- * not NULL set certain flags for more detailed error reporting.  Used
- * flags are:
+ * that matched the low-level search criteria or NULL.
+ *
+ * If R_FLAGS is not NULL set certain flags for more detailed error
+ * reporting.  Used flags are:
+ *
  * - LOOKUP_ALL_SUBKEYS_EXPIRED :: All Subkeys are expired or have
  *                                 been revoked.
+ * - LOOKUP_NOT_SELECTED :: No suitable key found
  *
  * This function needs to handle several different cases:
  *
@@ -3094,40 +3145,41 @@ merge_selfsigs (KBNODE keyblock)
  *
  */
 static kbnode_t
-finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
+finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
+               unsigned int *r_flags)
 {
   kbnode_t k;
 
-  /* If CTX->EXACT is set, the key or subkey that actually matched the
+  /* If WANT_EXACT is set, the key or subkey that actually matched the
      low-level search criteria.  */
   kbnode_t foundk = NULL;
   /* The user id (if any) that matched the low-level search criteria.  */
   PKT_user_id *foundu = NULL;
 
-#define USAGE_MASK  (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
-  unsigned int req_usage = (ctx->req_usage & USAGE_MASK);
-
-  /* Request the primary if we're certifying another key, and also
-     if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
-     do not understand signatures made by a signing subkey.  PGP 8
-     does. */
-  int req_prim = ((ctx->req_usage & PUBKEY_USAGE_CERT)
-                  || ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG)));
-
-  u32 curtime = make_timestamp ();
-
   u32 latest_date;
   kbnode_t latest_key;
   PKT_public_key *pk;
-
-  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  int req_prim;
+  u32 curtime = make_timestamp ();
 
   if (r_flags)
     *r_flags = 0;
 
+#define USAGE_MASK  (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
+  req_usage &= USAGE_MASK;
+
+  /* Request the primary if we're certifying another key, and also if
+   * signing data while --pgp6 or --pgp7 is on since pgp 6 and 7 do
+   * not understand signatures made by a signing subkey.  PGP 8 does. */
+  req_prim = ((req_usage & PUBKEY_USAGE_CERT)
+              || ((PGP6 || PGP7) && (req_usage & PUBKEY_USAGE_SIG)));
+
+
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+
   /* For an exact match mark the primary or subkey that matched the
      low-level search criteria.  */
-  if (ctx->exact)
+  if (want_exact)
     {
       for (k = keyblock; k; k = k->next)
        {
@@ -3262,7 +3314,7 @@ finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
    *     primary key, or,
    *
    *   - we're just considering the primary key.  */
-  if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
+  if ((!latest_key && !want_exact) || foundk == keyblock || req_prim)
     {
       if (DBG_LOOKUP && !foundk && !req_prim)
        log_debug ("\tno suitable subkeys found - trying primary\n");
@@ -3300,10 +3352,12 @@ finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
     {
       if (DBG_LOOKUP)
        log_debug ("\tno suitable key found -  giving up\n");
+      if (r_flags)
+        *r_flags |= LOOKUP_NOT_SELECTED;
       return NULL; /* Not found.  */
     }
 
-found:
+ found:
   if (DBG_LOOKUP)
     log_debug ("\tusing key %08lX\n",
               (ulong) keyid_from_pk (latest_key->pkt->pkt.public_key, NULL));
@@ -3408,12 +3462,10 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
         goto skip; /* No secret key available.  */
 
       /* Warning: node flag bits 0 and 1 should be preserved by
-       * merge_selfsigs.  For secret keys, premerge transferred the
-       * keys to the keyblock.  */
+       * merge_selfsigs.  */
       merge_selfsigs (keyblock);
-      found_key = finish_lookup (ctx, keyblock, &infoflags);
-      if (!found_key)
-        infoflags |= LOOKUP_NOT_SELECTED;
+      found_key = finish_lookup (keyblock, ctx->req_usage, ctx->exact,
+                                 &infoflags);
       print_status_key_considered (keyblock, infoflags);
       if (found_key)
        {
@@ -3503,6 +3555,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
 {
   gpg_error_t err = 0;
   const char *name;
+  kbnode_t keyblock;
   struct
   {
     int eof;
@@ -3510,6 +3563,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
     strlist_t sl;
     kbnode_t keyblock;
     kbnode_t node;
+    getkey_ctx_t ctx;
   } *c = *context;
 
   if (!c)
@@ -3525,6 +3579,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
     {
       /* Free the context.  */
       release_kbnode (c->keyblock);
+      getkey_end (c->ctx);
       xfree (c);
       *context = NULL;
       return 0;
@@ -3542,6 +3597,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
           do
             {
               name = NULL;
+              keyblock = NULL;
               switch (c->state)
                 {
                 case 0: /* First try to use the --default-key.  */
@@ -3564,24 +3620,60 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
                     c->state++;
                   break;
 
+                case 3: /* Init search context to try all keys.  */
+                  if (opt.try_all_secrets)
+                    {
+                      err = getkey_bynames (&c->ctx, NULL, NULL, 1, &keyblock);
+                      if (err)
+                        {
+                          release_kbnode (keyblock);
+                          keyblock = NULL;
+                          getkey_end (c->ctx);
+                          c->ctx = NULL;
+                        }
+                    }
+                  c->state++;
+                  break;
+
+                case 4: /* Get next item from the context.  */
+                  if (c->ctx)
+                    {
+                      err = getkey_next (c->ctx, NULL, &keyblock);
+                      if (err)
+                        {
+                          release_kbnode (keyblock);
+                          keyblock = NULL;
+                          getkey_end (c->ctx);
+                          c->ctx = NULL;
+                        }
+                    }
+                  else
+                    c->state++;
+                  break;
+
                 default: /* No more names to check - stop.  */
                   c->eof = 1;
                   return gpg_error (GPG_ERR_EOF);
                 }
             }
-          while (!name || !*name);
+          while ((!name || !*name) && !keyblock);
 
-          err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
-          if (err)
+          if (keyblock)
+            c->node = c->keyblock = keyblock;
+          else
             {
-              /* getkey_byname might return a keyblock even in the
-                 error case - I have not checked.  Thus better release
-                 it.  */
-              release_kbnode (c->keyblock);
-              c->keyblock = NULL;
+              err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
+              if (err)
+                {
+                  /* getkey_byname might return a keyblock even in the
+                     error case - I have not checked.  Thus better release
+                     it.  */
+                  release_kbnode (c->keyblock);
+                  c->keyblock = NULL;
+                }
+              else
+                c->node = c->keyblock;
             }
-          else
-            c->node = c->keyblock;
         }
 
       /* Get the next key from the current keyblock.  */
index 1f2d416..35d350e 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -81,6 +81,8 @@ enum cmd_and_opt_values
     aSym         = 'c',
     aDecrypt     = 'd',
     aEncr        = 'e',
+    oRecipientFile       = 'f',
+    oHiddenRecipientFile = 'F',
     oInteractive  = 'i',
     aListKeys    = 'k',
     oDryRun      = 'n',
@@ -118,6 +120,7 @@ enum cmd_and_opt_values
     aQuickLSignKey,
     aQuickAddUid,
     aQuickAddKey,
+    aQuickRevUid,
     aListConfig,
     aListGcryptConfig,
     aGPGConfList,
@@ -166,6 +169,7 @@ enum cmd_and_opt_values
     aServer,
     aTOFUPolicy,
 
+    oMimemode,
     oTextmode,
     oNoTextmode,
     oExpert,
@@ -216,6 +220,7 @@ enum cmd_and_opt_values
     oGnuPG,
     oRFC2440,
     oRFC4880,
+    oRFC4880bis,
     oOpenPGP,
     oPGP6,
     oPGP7,
@@ -246,6 +251,7 @@ enum cmd_and_opt_values
     oNoMDCWarn,
     oNoArmor,
     oNoDefKeyring,
+    oNoKeyring,
     oNoGreeting,
     oNoTTY,
     oNoOptions,
@@ -298,7 +304,9 @@ enum cmd_and_opt_values
     oKeyServer,
     oKeyServerOptions,
     oImportOptions,
+    oImportFilter,
     oExportOptions,
+    oExportFilter,
     oListOptions,
     oVerifyOptions,
     oTempDir,
@@ -430,6 +438,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aQuickAddUid,  "quick-adduid",
               N_("quickly add a new user-id")),
   ARGPARSE_c (aQuickAddKey,  "quick-addkey", "@"),
+  ARGPARSE_c (aQuickRevUid,  "quick-revuid",
+              N_("quickly revoke a user-id")),
   ARGPARSE_c (aFullKeygen,  "full-gen-key" ,
               N_("full featured key pair generation")),
   ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
@@ -499,6 +509,8 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
   ARGPARSE_s_s (oHiddenRecipient, "hidden-recipient", "@"),
+  ARGPARSE_s_s (oRecipientFile, "recipient-file", "@"),
+  ARGPARSE_s_s (oHiddenRecipientFile, "hidden-recipient-file", "@"),
   ARGPARSE_s_s (oRecipient, "remote-user", "@"),  /* (old option name) */
   ARGPARSE_s_s (oDefRecipient, "default-recipient", "@"),
   ARGPARSE_s_n (oDefRecipientSelf,  "default-recipient-self", "@"),
@@ -521,8 +533,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_i (oBZ2CompressLevel, "bzip2-compress-level", "@"),
   ARGPARSE_s_n (oBZ2DecompressLowmem, "bzip2-decompress-lowmem", "@"),
 
+  ARGPARSE_s_n (oMimemode, "mimemode", "@"),
   ARGPARSE_s_n (oTextmodeShort, NULL, "@"),
-  ARGPARSE_s_n (oTextmode,      "textmode", N_("use canonical text mode")),
+  ARGPARSE_s_n (oTextmode,   "textmode", N_("use canonical text mode")),
   ARGPARSE_s_n (oNoTextmode, "no-textmode", "@"),
 
   ARGPARSE_s_n (oExpert,      "expert", "@"),
@@ -568,7 +581,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
   ARGPARSE_s_s (oKeyServerOptions, "keyserver-options", "@"),
   ARGPARSE_s_s (oImportOptions, "import-options", "@"),
+  ARGPARSE_s_s (oImportFilter,  "import-filter", "@"),
   ARGPARSE_s_s (oExportOptions, "export-options", "@"),
+  ARGPARSE_s_s (oExportFilter,  "export-filter", "@"),
   ARGPARSE_s_s (oListOptions,   "list-options", "@"),
   ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"),
 
@@ -599,6 +614,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oGnuPG, "no-pgp8", "@"),
   ARGPARSE_s_n (oRFC2440, "rfc2440", "@"),
   ARGPARSE_s_n (oRFC4880, "rfc4880", "@"),
+  ARGPARSE_s_n (oRFC4880bis, "rfc4880bis", "@"),
   ARGPARSE_s_n (oOpenPGP, "openpgp", N_("use strict OpenPGP behavior")),
   ARGPARSE_s_n (oPGP6, "pgp6", "@"),
   ARGPARSE_s_n (oPGP7, "pgp7", "@"),
@@ -672,6 +688,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oNoArmor, "no-armor", "@"),
   ARGPARSE_s_n (oNoArmor, "no-armour", "@"),
   ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
+  ARGPARSE_s_n (oNoKeyring, "no-keyring", "@"),
   ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
   ARGPARSE_s_n (oNoOptions, "no-options", "@"),
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
@@ -2028,6 +2045,7 @@ parse_tofu_db_format (const char *db_format)
     }
 }
 
+
 /* This function called to initialized a new control object.  It is
    assumed that this object has been zeroed out before calling this
    function. */
@@ -2155,15 +2173,19 @@ main (int argc, char **argv)
     int pwfd = -1;
     int fpr_maybe_cmd = 0; /* --fingerprint maybe a command.  */
     int any_explicit_recipient = 0;
-    int require_secmem=0,got_secmem=0;
+    int require_secmem = 0;
+    int got_secmem = 0;
     struct assuan_malloc_hooks malloc_hooks;
     ctrl_t ctrl;
 
+    static int print_dane_records;
+    static int print_pka_records;
+
+
 #ifdef __riscos__
     opt.lock_once = 1;
 #endif /* __riscos__ */
 
-
     /* Please note that we may running SUID(ROOT), so be very CAREFUL
        when adding any stuff between here and the call to
        secmem_init() somewhere after the option parsing. */
@@ -2432,6 +2454,7 @@ main (int argc, char **argv)
          case aQuickKeygen:
          case aQuickAddUid:
          case aQuickAddKey:
+         case aQuickRevUid:
          case aExportOwnerTrust:
          case aImportOwnerTrust:
           case aRebuildKeydbCaches:
@@ -2598,7 +2621,15 @@ main (int argc, char **argv)
            }
            break;
          case oNoArmor: opt.no_armor=1; opt.armor=0; break;
-         case oNoDefKeyring: default_keyring = 0; break;
+
+         case oNoDefKeyring:
+            if (default_keyring > 0)
+              default_keyring = 0;
+            break;
+         case oNoKeyring:
+            default_keyring = -1;
+            break;
+
          case oNoGreeting: nogreeting = 1; break;
          case oNoVerbose:
             opt.verbose = 0;
@@ -2686,6 +2717,9 @@ main (int argc, char **argv)
             /* Dummy so that gpg 1.4 conf files can work. Should
                eventually be removed.  */
            break;
+          case oRFC4880bis:
+            opt.flags.rfc4880bis = 1;
+            /* fall thru.  */
          case oOpenPGP:
          case oRFC4880:
            /* This is effectively the same as RFC2440, but with
@@ -2814,46 +2848,56 @@ main (int argc, char **argv)
             else
               opt.s2k_count = 0;  /* Auto-calibrate when needed.  */
            break;
-         case oNoEncryptTo: opt.no_encrypt_to = 1; break;
-         case oEncryptTo: /* store the recipient in the second list */
+
+         case oRecipient:
+         case oHiddenRecipient:
+         case oRecipientFile:
+         case oHiddenRecipientFile:
+            /* Store the recipient.  Note that we also store the
+             * option as private data in the flags.  This is achieved
+             * by shifting the option value to the left so to keep
+             * enough space for the flags.  */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
+           sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
             if (configfp)
               sl->flags |= PK_LIST_CONFIG;
+            if (pargs.r_opt == oHiddenRecipient
+                || pargs.r_opt == oHiddenRecipientFile)
+              sl->flags |= PK_LIST_HIDDEN;
+            if (pargs.r_opt == oRecipientFile
+                || pargs.r_opt == oHiddenRecipientFile)
+              sl->flags |= PK_LIST_FROM_FILE;
+            any_explicit_recipient = 1;
            break;
-         case oHiddenEncryptTo: /* store the recipient in the second list */
+
+         case oEncryptTo:
+         case oHiddenEncryptTo:
+            /* Store an additional recipient.  */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT)
-                         | PK_LIST_ENCRYPT_TO|PK_LIST_HIDDEN);
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
             if (configfp)
               sl->flags |= PK_LIST_CONFIG;
+            if (pargs.r_opt == oHiddenEncryptTo)
+              sl->flags |= PK_LIST_HIDDEN;
            break;
+
+         case oNoEncryptTo:
+            opt.no_encrypt_to = 1;
+            break;
           case oEncryptToDefaultKey:
             opt.encrypt_to_default_key = configfp ? 2 : 1;
             break;
-         case oRecipient: /* store the recipient */
-           sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
-            if (configfp)
-              sl->flags |= PK_LIST_CONFIG;
-            any_explicit_recipient = 1;
-           break;
-         case oHiddenRecipient: /* store the recipient with a flag */
-           sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
-            if (configfp)
-              sl->flags |= PK_LIST_CONFIG;
-            any_explicit_recipient = 1;
-           break;
 
          case oTrySecretKey:
            add_to_strlist2 (&opt.secret_keys_to_try,
                              pargs.r.ret_str, utf8_strings);
            break;
 
+          case oMimemode: opt.mimemode = opt.textmode = 1; break;
          case oTextmodeShort: opt.textmode = 2; break;
          case oTextmode: opt.textmode=1;  break;
-         case oNoTextmode: opt.textmode=0;  break;
+         case oNoTextmode: opt.textmode=opt.mimemode=0;  break;
+
          case oExpert: opt.expert = 1; break;
          case oNoExpert: opt.expert = 0; break;
          case oDefSigExpire:
@@ -3022,6 +3066,11 @@ main (int argc, char **argv)
                  log_error(_("invalid import options\n"));
              }
            break;
+         case oImportFilter:
+           rc = parse_and_set_import_filter (pargs.r.ret_str);
+           if (rc)
+              log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
+           break;
          case oExportOptions:
            if(!parse_export_options(pargs.r.ret_str,&opt.export_options,1))
              {
@@ -3032,6 +3081,11 @@ main (int argc, char **argv)
                  log_error(_("invalid export options\n"));
              }
            break;
+         case oExportFilter:
+           rc = parse_and_set_export_filter (pargs.r.ret_str);
+           if (rc)
+              log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
+           break;
          case oListOptions:
            if(!parse_list_options(pargs.r.ret_str))
              {
@@ -3136,8 +3190,8 @@ main (int argc, char **argv)
          case oFastListMode: opt.fast_list_mode = 1; break;
          case oFixedListMode: /* Dummy */ break;
           case oLegacyListMode: opt.legacy_list_mode = 1; break;
-         case oPrintPKARecords: opt.print_pka_records = 1; break;
-         case oPrintDANERecords: opt.print_dane_records = 1; break;
+         case oPrintPKARecords: print_pka_records = 1; break;
+         case oPrintDANERecords: print_dane_records = 1; break;
          case oListOnly: opt.list_only=1; break;
          case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
          case oIgnoreValidFrom: opt.ignore_valid_from = 1; break;
@@ -3360,6 +3414,18 @@ main (int argc, char **argv)
     xfree (save_configname);
     xfree (default_configname);
 
+    if (print_dane_records)
+      log_error ("invalid option \"%s\"; use \"%s\" instead\n",
+                 "--print-dane-records",
+                 "--export-options export-dane");
+    if (print_pka_records)
+      log_error ("invalid option \"%s\"; use \"%s\" instead\n",
+                 "--print-pks-records",
+                 "--export-options export-pka");
+    if (log_get_errorcount (0))
+      g10_exit(2);
+
+
     if( nogreeting )
        greeting = 0;
 
@@ -3399,6 +3465,13 @@ main (int argc, char **argv)
     if( may_coredump && !opt.quiet )
        log_info(_("WARNING: program may create a core file!\n"));
 
+    if (opt.flags.rfc4880bis)
+       log_info ("WARNING: using experimental features from RFC4880bis!\n");
+    else
+      {
+        opt.mimemode = 0; /* This will use text mode instead.  */
+      }
+
     if (eyes_only) {
       if (opt.set_filename)
          log_info(_("WARNING: %s overrides %s\n"),
@@ -3676,14 +3749,15 @@ main (int argc, char **argv)
     if( opt.verbose > 1 )
        set_packet_list_mode(1);
 
-    /* Add the keyrings, but not for some special commands.
-       We always need to add the keyrings if we are running under
-       SELinux, this is so that the rings are added to the list of
-       secured files. */
-    if( ALWAYS_ADD_KEYRINGS
-        || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest) )
+    /* Add the keyrings, but not for some special commands.  We always
+     * need to add the keyrings if we are running under SELinux, this
+     * is so that the rings are added to the list of secured files.
+     * We do not add any keyring if --no-keyring has been used.  */
+    if (default_keyring >= 0
+        && (ALWAYS_ADD_KEYRINGS
+            || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
       {
-       if (!nrings || default_keyring)  /* Add default ring. */
+       if (!nrings || default_keyring > 0)  /* Add default ring. */
            keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
                                 KEYDB_RESOURCE_FLAG_DEFAULT);
        for (sl = nrings; sl; sl = sl->next )
@@ -3777,6 +3851,7 @@ main (int argc, char **argv)
       case aQuickKeygen:
       case aQuickAddUid:
       case aQuickAddKey:
+      case aQuickRevUid:
       case aFullKeygen:
       case aKeygen:
       case aImport:
@@ -4196,6 +4271,18 @@ main (int argc, char **argv)
         }
        break;
 
+      case aQuickRevUid:
+        {
+          const char *uid, *uidtorev;
+
+          if (argc != 2)
+            wrong_args ("--quick-revuid USER-ID USER-ID-TO-REVOKE");
+          uid = *argv++; argc--;
+          uidtorev = *argv++; argc--;
+          keyedit_quick_revuid (ctrl, uid, uidtorev);
+        }
+       break;
+
       case aFastImport:
         opt.import_options |= IMPORT_FAST;
       case aImport:
@@ -4648,7 +4735,6 @@ main (int argc, char **argv)
        break;
 
       case aListPackets:
-       opt.list_packets=2;
       default:
        if( argc > 1 )
            wrong_args(_("[filename]"));
@@ -4677,8 +4763,8 @@ main (int argc, char **argv)
                }
            }
            if( cmd == aListPackets ) {
-               set_packet_list_mode(1);
                opt.list_packets=1;
+               set_packet_list_mode(1);
            }
            rc = proc_packets (ctrl, NULL, a );
            if( rc )
index 2aed10c..d08dc5a 100644 (file)
@@ -167,6 +167,8 @@ main( int argc, char **argv )
   opt.command_fd = -1; /* no command fd */
   opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE;
   opt.trust_model = TM_ALWAYS;
+  opt.no_sig_cache = 1;
+  opt.flags.require_cross_cert = 1;
   opt.batch = 1;
 
   opt.weak_digests = NULL;
@@ -365,6 +367,17 @@ keyserver_import_keyid (u32 *keyid, void *dummy)
 }
 
 int
+keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
+                        struct keyserver_spec *keyserver)
+{
+  (void)ctrl;
+  (void)fprint;
+  (void)fprint_len;
+  (void)keyserver;
+  return -1;
+}
+
+int
 keyserver_import_cert (const char *name)
 {
   (void)name;
@@ -405,6 +418,17 @@ keyserver_import_ldap (const char *name)
   return -1;
 }
 
+
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+  (void)ctrl;
+  (void)fname;
+  (void)r_keyblock;
+  return -1;
+}
+
+
 /* Stub:
  * No encryption here but mainproc links to these functions.
  */
index 7c0d1e2..375bd03 100644 (file)
@@ -1,6 +1,6 @@
 /* import.c - import a key into our key storage.
  * Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
- * Copyright (C) 2014  Werner Koch
+ * Copyright (C) 2014, 2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
 #include "i18n.h"
 #include "ttyio.h"
 #include "status.h"
+#include "recsel.h"
 #include "keyserver-internal.h"
 #include "call-agent.h"
 #include "../common/membuf.h"
+#include "../common/init.h"
+#include "../common/mbox-util.h"
+
 
 struct import_stats_s
 {
@@ -60,6 +64,28 @@ struct import_stats_s
 };
 
 
+/* Node flag to indicate that a user ID or a subkey has a
+ * valid self-signature.  */
+#define NODE_GOOD_SELFSIG  1
+/* Node flag to indicate that a user ID or subkey has
+ * an invalid self-signature.  */
+#define NODE_BAD_SELFSIG   2
+/* Node flag to indicate that the node shall be deleted.  */
+#define NODE_DELETION_MARK 4
+/* A node flag used to temporary mark a node. */
+#define NODE_FLAG_A  8
+
+
+/* A global variable to store the selector created from
+ * --import-filter keep-uid=EXPR.
+ *
+ * FIXME: We should put this into the CTRL object but that requires a
+ * lot more changes right now.
+ */
+static recsel_expr_t import_keep_uid;
+
+
+
 static int import (ctrl_t ctrl,
                    IOBUF inp, const char* fname, struct import_stats_s *stats,
                   unsigned char **fpr, size_t *fpr_len, unsigned int options,
@@ -68,32 +94,36 @@ static int read_block (IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root,
                        int *r_v3keys);
 static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
 static int import_one (ctrl_t ctrl,
-                       const char *fname, kbnode_t keyblock,
+                       kbnode_t keyblock,
                        struct import_stats_s *stats,
                        unsigned char **fpr, size_t *fpr_len,
                        unsigned int options, int from_sk, int silent,
                        import_screener_t screener, void *screener_arg);
-static int import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
+static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
                               struct import_stats_s *stats, int batch,
                               unsigned int options, int for_migration,
                               import_screener_t screener, void *screener_arg);
-static int import_revoke_cert( const char *fname, kbnode_t node,
-                               struct import_stats_s *stats);
-static int chk_self_sigs (const char *fname, kbnode_t keyblock,
-                         PKT_public_key *pk, u32 *keyid, int *non_self );
-static int delete_inv_parts (const char *fname, kbnode_t keyblock,
-                            u32 *keyid, unsigned int options );
-static int merge_blocks (const char *fname, kbnode_t keyblock_orig,
+static int import_revoke_cert (kbnode_t node, struct import_stats_s *stats);
+static int chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self);
+static int delete_inv_parts (kbnode_t keyblock,
+                             u32 *keyid, unsigned int options);
+static int merge_blocks (kbnode_t keyblock_orig,
                         kbnode_t keyblock, u32 *keyid,
                         int *n_uids, int *n_sigs, int *n_subk );
-static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-                            const char *fname, u32 *keyid );
-static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-                            const char *fname, u32 *keyid );
-static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-                            const char *fname, u32 *keyid );
-static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-                            const char *fname, u32 *keyid );
+static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs);
+static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs);
+static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs);
+static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
+
+
+\f
+static void
+cleanup_import_globals (void)
+{
+  recsel_release (import_keep_uid);
+  import_keep_uid = NULL;
+}
+
 
 int
 parse_import_options(char *str,unsigned int *options,int noisy)
@@ -112,6 +142,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
       {"fast-import",IMPORT_FAST,NULL,
        N_("do not update the trustdb after import")},
 
+      {"import-show",IMPORT_SHOW,NULL,
+       N_("show key during import")},
+
       {"merge-only",IMPORT_MERGE_ONLY,NULL,
        N_("only accept updates to existing keys")},
 
@@ -121,6 +154,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
       {"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
        N_("remove as much as possible from key after import")},
 
+      {"import-export", IMPORT_EXPORT, NULL,
+       N_("run import filters and export key immediately")},
+
       /* Aliases for backward compatibility */
       {"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
       {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
@@ -137,6 +173,39 @@ parse_import_options(char *str,unsigned int *options,int noisy)
 }
 
 
+/* Parse and set an import filter from string.  STRING has the format
+ * "NAME=EXPR" with NAME being the name of the filter.  Spaces before
+ * and after NAME are not allowed.  If this function is all called
+ * several times all expressions for the same NAME are concatenated.
+ * Supported filter names are:
+ *
+ *  - keep-uid :: If the expression evaluates to true for a certain
+ *                user ID packet, that packet and all it dependencies
+ *                will be imported.  The expression may use these
+ *                variables:
+ *
+ *                - uid  :: The entire user ID.
+ *                - mbox :: The mail box part of the user ID.
+ *                - primary :: Evaluate to true for the primary user ID.
+ */
+gpg_error_t
+parse_and_set_import_filter (const char *string)
+{
+  gpg_error_t err;
+
+  /* Auto register the cleanup function.  */
+  register_mem_cleanup_func (cleanup_import_globals);
+
+  if (!strncmp (string, "keep-uid=", 9))
+    err = recsel_parse_expr (&import_keep_uid, string+9);
+  else
+    err = gpg_error (GPG_ERR_INV_NAME);
+
+  return err;
+}
+
+
+
 import_stats_t
 import_new_stats_handle (void)
 {
@@ -151,6 +220,113 @@ import_release_stats_handle (import_stats_t p)
 }
 
 
+/* Read a key from a file.  Only the first key in the file is
+ * considered and stored at R_KEYBLOCK.  FNAME is the name of the
+ * file.
+ */
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+  gpg_error_t err;
+  iobuf_t inp;
+  PACKET *pending_pkt = NULL;
+  kbnode_t keyblock = NULL;
+  u32 keyid[2];
+  int v3keys;   /* Dummy */
+  int non_self; /* Dummy */
+
+  (void)ctrl;
+
+  *r_keyblock = NULL;
+
+  inp = iobuf_open (fname);
+  if (!inp)
+    err = gpg_error_from_syserror ();
+  else if (is_secured_file (iobuf_get_fd (inp)))
+    {
+      iobuf_close (inp);
+      inp = NULL;
+      err = gpg_error (GPG_ERR_EPERM);
+    }
+  else
+    err = 0;
+  if (err)
+    {
+      log_error (_("can't open '%s': %s\n"),
+                 iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+                 gpg_strerror (err));
+      if (gpg_err_code (err) == GPG_ERR_ENOENT)
+        err = gpg_error (GPG_ERR_NO_PUBKEY);
+      goto leave;
+    }
+
+  /* Push the armor filter.  */
+  {
+    armor_filter_context_t *afx;
+    afx = new_armor_context ();
+    afx->only_keyblocks = 1;
+    push_armor_filter (afx, inp);
+    release_armor_context (afx);
+  }
+
+  /* Read the first non-v3 keyblock.  */
+  while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
+    {
+      if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
+        break;
+      log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
+      release_kbnode (keyblock);
+      keyblock = NULL;
+    }
+  if (err)
+    {
+      if (gpg_err_code (err) != GPG_ERR_INV_KEYRING)
+        log_error (_("error reading '%s': %s\n"),
+                   iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+                   gpg_strerror (err));
+      goto leave;
+    }
+
+  keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
+
+  if (!find_next_kbnode (keyblock, PKT_USER_ID))
+    {
+      err = gpg_error (GPG_ERR_NO_USER_ID);
+      goto leave;
+    }
+
+  collapse_uids (&keyblock);
+
+  clear_kbnode_flags (keyblock);
+  if (chk_self_sigs (keyblock, keyid, &non_self))
+    {
+      err = gpg_error (GPG_ERR_INV_KEYRING);
+      goto leave;
+    }
+
+  if (!delete_inv_parts (keyblock, keyid, 0) )
+    {
+      err = gpg_error (GPG_ERR_NO_USER_ID);
+      goto leave;
+    }
+
+  *r_keyblock = keyblock;
+  keyblock = NULL;
+
+ leave:
+  if (inp)
+    {
+      iobuf_close (inp);
+      /* Must invalidate that ugly cache to actually close the file. */
+      iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+    }
+  release_kbnode (keyblock);
+  /* FIXME: Do we need to free PENDING_PKT ? */
+  return err;
+}
+
+
+
 /*
  * Import the public keys from the given filename. Input may be armored.
  * This function rejects all keys which are not validly self signed on at
@@ -328,16 +504,16 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
     {
       stats->v3keys += v3keys;
       if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
-        rc = import_one (ctrl, fname, keyblock,
+        rc = import_one (ctrl, keyblock,
                          stats, fpr, fpr_len, options, 0, 0,
                          screener, screener_arg);
       else if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
-        rc = import_secret_one (ctrl, fname, keyblock, stats,
+        rc = import_secret_one (ctrl, keyblock, stats,
                                 opt.batch, options, 0,
                                 screener, screener_arg);
       else if (keyblock->pkt->pkttype == PKT_SIGNATURE
                && keyblock->pkt->pkt.signature->sig_class == 0x20 )
-        rc = import_revoke_cert( fname, keyblock, stats );
+        rc = import_revoke_cert (keyblock, stats);
       else
         {
           log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
@@ -401,7 +577,7 @@ import_old_secring (ctrl_t ctrl, const char *fname)
   while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
     {
       if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
-        err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1,
+        err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
                                  NULL, NULL);
       release_kbnode (keyblock);
       if (err)
@@ -707,8 +883,8 @@ fix_pks_corruption (kbnode_t keyblock)
            }
          else
            {
-             sknode->flag |= 1; /* Mark it good so we don't need to
-                                    check it again */
+              /* Mark it good so we don't need to check it again */
+             sknode->flag |= NODE_GOOD_SELFSIG;
              changed = 1;
              break;
            }
@@ -921,6 +1097,74 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
 }
 
 
+/* Helper for apply_keep_uid_filter.  */
+static const char *
+filter_getval (void *cookie, const char *propname)
+{
+  kbnode_t node = cookie;
+  const char *result;
+
+  if (node->pkt->pkttype == PKT_USER_ID)
+    {
+      if (!strcmp (propname, "uid"))
+        result = node->pkt->pkt.user_id->name;
+      else if (!strcmp (propname, "mbox"))
+        {
+          if (!node->pkt->pkt.user_id->mbox)
+            {
+              node->pkt->pkt.user_id->mbox
+                = mailbox_from_userid (node->pkt->pkt.user_id->name);
+            }
+          return node->pkt->pkt.user_id->mbox;
+        }
+      else if (!strcmp (propname, "primary"))
+        result = node->pkt->pkt.user_id->is_primary? "1":"0";
+      else
+        result = NULL;
+    }
+  else
+    result = NULL;
+
+  return result;
+}
+
+/*
+ * Apply the keep-uid filter to the keyblock.  The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+  kbnode_t node;
+
+  for (node = keyblock->next; node; node = node->next )
+    {
+      if (node->pkt->pkttype == PKT_USER_ID)
+        {
+          if (!recsel_select (selector, filter_getval, node))
+            {
+
+              /* log_debug ("keep-uid: deleting '%s'\n", */
+              /*            node->pkt->pkt.user_id->name); */
+              /* The UID packet and all following packets up to the
+               * next UID or a subkey.  */
+              delete_kbnode (node);
+              for (; node->next
+                     && node->next->pkt->pkttype != PKT_USER_ID
+                     && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
+                     && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
+                   node = node->next)
+                delete_kbnode (node->next);
+           }
+          /* else */
+          /*   log_debug ("keep-uid: keeping '%s'\n", */
+          /*              node->pkt->pkt.user_id->name); */
+        }
+    }
+}
+
+
 /*
  * Try to import one keyblock. Return an error only in serious cases,
  * but never for an invalid keyblock.  It uses log_error to increase
@@ -930,13 +1174,13 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
  */
 static int
 import_one (ctrl_t ctrl,
-            const char *fname, kbnode_t keyblock, struct import_stats_s *stats,
+            kbnode_t keyblock, struct import_stats_s *stats,
            unsigned char **fpr, size_t *fpr_len, unsigned int options,
            int from_sk, int silent,
             import_screener_t screener, void *screener_arg)
 {
   PKT_public_key *pk;
-  PKT_public_key *pk_orig;
+  PKT_public_key *pk_orig = NULL;
   kbnode_t node, uidnode;
   kbnode_t keyblock_orig = NULL;
   byte fpr2[MAX_FINGERPRINT_LEN];
@@ -949,6 +1193,7 @@ import_one (ctrl_t ctrl,
   int non_self = 0;
   size_t an;
   char pkstrbuf[PUBKEY_STRING_SIZE];
+  int merge_keys_done = 0;
 
   /* Get the key and print some info about it. */
   node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@@ -1019,26 +1264,28 @@ import_one (ctrl_t ctrl,
     log_info (_("key %s: PKS subkey corruption repaired\n"),
               keystr_from_pk(pk));
 
-  rc = chk_self_sigs( fname, keyblock , pk, keyid, &non_self );
-  if (rc )
-    return rc== -1? 0:rc;
+  if (chk_self_sigs (keyblock, keyid, &non_self))
+    return 0;  /* Invalid keyblock - error already printed.  */
 
   /* If we allow such a thing, mark unsigned uids as valid */
   if (opt.allow_non_selfsigned_uid)
     {
       for (node=keyblock; node; node = node->next )
-        if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
+        if (node->pkt->pkttype == PKT_USER_ID
+            && !(node->flag & NODE_GOOD_SELFSIG)
+            && !(node->flag & NODE_BAD_SELFSIG) )
           {
             char *user=utf8_to_native(node->pkt->pkt.user_id->name,
                                       node->pkt->pkt.user_id->len,0);
-            node->flag |= 1;
+            /* Fake a good signature status for the user id.  */
+            node->flag |= NODE_GOOD_SELFSIG;
             log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"),
                       keystr_from_pk(pk),user);
             xfree(user);
          }
     }
 
-  if (!delete_inv_parts( fname, keyblock, keyid, options ) )
+  if (!delete_inv_parts (keyblock, keyid, options ) )
     {
       if (!silent)
         {
@@ -1050,6 +1297,46 @@ import_one (ctrl_t ctrl,
       return 0;
     }
 
+  /* Get rid of deleted nodes.  */
+  commit_kbnode (&keyblock);
+
+  /* Apply import filter.  */
+  if (import_keep_uid)
+    {
+      apply_keep_uid_filter (keyblock, import_keep_uid);
+      commit_kbnode (&keyblock);
+    }
+
+
+  /* Show the key in the form it is merged or inserted.  We skip this
+   * if "import-export" is also active without --armor or the output
+   * file has explicily been given. */
+  if ((options & IMPORT_SHOW)
+      && !((options & IMPORT_EXPORT) && !opt.armor && !opt.outfile))
+    {
+      merge_keys_and_selfsig (keyblock);
+      merge_keys_done = 1;
+      /* Note that we do not want to show the validity because the key
+       * has not yet imported.  */
+      list_keyblock_direct (ctrl, keyblock, 0, 0, 1, 1);
+      es_fflush (es_stdout);
+    }
+
+  /* Write the keyblock to the output and do not actually import.  */
+  if ((options & IMPORT_EXPORT))
+    {
+      if (!merge_keys_done)
+        {
+          merge_keys_and_selfsig (keyblock);
+          merge_keys_done = 1;
+        }
+      rc = write_keyblock_to_output (keyblock, opt.armor, opt.export_options);
+      goto leave;
+    }
+
+  if (opt.dry_run)
+    goto leave;
+
   /* Do we have this key already in one of our pubrings ? */
   pk_orig = xmalloc_clear( sizeof *pk_orig );
   rc = get_pubkey_byfprint_fast (pk_orig, fpr2, fpr2len);
@@ -1170,7 +1457,7 @@ import_one (ctrl_t ctrl,
       clear_kbnode_flags( keyblock_orig );
       clear_kbnode_flags( keyblock );
       n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
-      rc = merge_blocks( fname, keyblock_orig, keyblock,
+      rc = merge_blocks (keyblock_orig, keyblock,
                          keyid, &n_uids, &n_sigs, &n_subk );
       if (rc )
         {
@@ -1258,7 +1545,7 @@ import_one (ctrl_t ctrl,
       keydb_release (hd); hd = NULL;
     }
 
 leave:
+ leave:
   if (mod_key || new_key || same_key)
     {
       /* A little explanation for this: we fill in the fingerprint
@@ -1429,6 +1716,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
           else
             {
               const char *curvename = openpgp_oid_to_curve (curvestr, 1);
+              gcry_sexp_release (curve);
               err = gcry_sexp_build (&curve, NULL, "(curve %s)",
                                      curvename?curvename:curvestr);
               xfree (curvestr);
@@ -1654,7 +1942,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
  * with the trust calculation.
  */
 static int
-import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
+import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
                    struct import_stats_s *stats, int batch, unsigned int options,
                    int for_migration,
                    import_screener_t screener, void *screener_arg)
@@ -1754,7 +2042,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
       /* Note that this outputs an IMPORT_OK status message for the
         public key block, and below we will output another one for
         the secret keys.  FIXME?  */
-      import_one (ctrl, fname, pub_keyblock, stats,
+      import_one (ctrl, pub_keyblock, stats,
                  NULL, NULL, options, 1, for_migration,
                   screener, screener_arg);
 
@@ -1822,8 +2110,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
  * Import a revocation certificate; this is a single signature packet.
  */
 static int
-import_revoke_cert (const char *fname, kbnode_t node,
-                    struct import_stats_s *stats)
+import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
 {
   PKT_public_key *pk = NULL;
   kbnode_t onode;
@@ -1832,8 +2119,6 @@ import_revoke_cert (const char *fname, kbnode_t node,
   u32 keyid[2];
   int rc = 0;
 
-  (void)fname;
-
   log_assert (!node->next );
   log_assert (node->pkt->pkttype == PKT_SIGNATURE );
   log_assert (node->pkt->pkt.signature->sig_class == 0x20 );
@@ -1949,18 +2234,21 @@ import_revoke_cert (const char *fname, kbnode_t node,
 }
 
 
-/*
- * Loop over the keyblock and check all self signatures.
- * Mark all user-ids with a self-signature by setting flag bit 0.
- * Mark all user-ids with an invalid self-signature by setting bit 1.
- * This works also for subkeys, here the subkey is marked.  Invalid or
- * extra subkey sigs (binding or revocation) are marked for deletion.
- * non_self is set to true if there are any sigs other than self-sigs
+/* Loop over the keyblock and check all self signatures.  On return
+ * the following bis in the node flags are set:
+ *
+ * - NODE_GOOD_SELFSIG  :: User ID or subkey has a self-signature
+ * - NODE_BAD_SELFSIG   :: Used ID or subkey has an invalid self-signature
+ * - NODE_DELETION_MARK :: This node shall be deleted
+ *
+ * NON_SELF is set to true if there are any sigs other than self-sigs
  * in this keyblock.
+ *
+ * Returns 0 on success or -1 (but not an error code) if the keyblock
+ * is invalid.
  */
 static int
-chk_self_sigs (const char *fname, kbnode_t keyblock,
-              PKT_public_key *pk, u32 *keyid, int *non_self )
+chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self )
 {
   kbnode_t n, knode = NULL;
   PKT_signature *sig;
@@ -1968,9 +2256,6 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
   u32 bsdate=0, rsdate=0;
   kbnode_t bsnode = NULL, rsnode = NULL;
 
-  (void)fname;
-  (void)pk;
-
   for (n=keyblock; (n = find_next_kbnode (n, 0)); )
     {
       if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
@@ -2009,7 +2294,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
             }
 
           /* If it hasn't been marked valid yet, keep trying.  */
-          if (!(unode->flag&1))
+          if (!(unode->flag & NODE_GOOD_SELFSIG))
             {
               rc = check_key_signature (keyblock, n, NULL);
               if ( rc )
@@ -2029,7 +2314,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                     }
                 }
               else
-                unode->flag |= 1; /* Mark that signature checked. */
+                unode->flag |= NODE_GOOD_SELFSIG;
             }
         }
       else if (IS_KEY_SIG (sig))
@@ -2042,7 +2327,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                           _("key %s: unsupported public key algorithm\n"):
                           _("key %s: invalid direct key signature\n"),
                           keystr (keyid));
-              n->flag |= 4;
+              n->flag |= NODE_DELETION_MARK;
             }
         }
       else if ( IS_SUBKEY_SIG (sig) )
@@ -2056,7 +2341,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
               if (opt.verbose)
                 log_info (_("key %s: no subkey for key binding\n"),
                           keystr (keyid));
-              n->flag |= 4; /* delete this */
+              n->flag |= NODE_DELETION_MARK;
             }
           else
             {
@@ -2069,19 +2354,19 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                                 " algorithm\n"):
                               _("key %s: invalid subkey binding\n"),
                               keystr (keyid));
-                  n->flag |= 4;
+                  n->flag |= NODE_DELETION_MARK;
                 }
               else
                 {
                   /* It's valid, so is it newer? */
                   if (sig->timestamp >= bsdate)
                     {
-                      knode->flag |= 1;  /* The subkey is valid.  */
+                      knode->flag |= NODE_GOOD_SELFSIG; /* Subkey is valid.  */
                       if (bsnode)
                         {
                           /* Delete the last binding sig since this
                              one is newer */
-                          bsnode->flag |= 4;
+                          bsnode->flag |= NODE_DELETION_MARK;
                           if (opt.verbose)
                             log_info (_("key %s: removed multiple subkey"
                                         " binding\n"),keystr(keyid));
@@ -2091,7 +2376,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                       bsdate = sig->timestamp;
                     }
                   else
-                    n->flag |= 4; /* older */
+                    n->flag |= NODE_DELETION_MARK; /* older */
                 }
             }
         }
@@ -2107,7 +2392,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
               if (opt.verbose)
                 log_info (_("key %s: no subkey for key revocation\n"),
                           keystr(keyid));
-              n->flag |= 4; /* delete this */
+              n->flag |= NODE_DELETION_MARK;
             }
           else
             {
@@ -2120,7 +2405,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                                 " key algorithm\n"):
                               _("key %s: invalid subkey revocation\n"),
                               keystr(keyid));
-                  n->flag |= 4;
+                  n->flag |= NODE_DELETION_MARK;
                 }
               else
                 {
@@ -2131,7 +2416,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                         {
                           /* Delete the last revocation sig since
                              this one is newer.  */
-                          rsnode->flag |= 4;
+                          rsnode->flag |= NODE_DELETION_MARK;
                           if (opt.verbose)
                             log_info (_("key %s: removed multiple subkey"
                                         " revocation\n"),keystr(keyid));
@@ -2141,7 +2426,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                       rsdate = sig->timestamp;
                     }
                   else
-                    n->flag |= 4; /* older */
+                    n->flag |= NODE_DELETION_MARK; /* older */
                 }
             }
         }
@@ -2151,28 +2436,25 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
 }
 
 
-/****************
- * delete all parts which are invalid and those signatures whose
- * public key algorithm is not available in this implemenation;
- * but consider RSA as valid, because parse/build_packets knows
- * about it.
- * returns: true if at least one valid user-id is left over.
+/* Delete all parts which are invalid and those signatures whose
+ * public key algorithm is not available in this implemenation; but
+ * consider RSA as valid, because parse/build_packets knows about it.
+ *
+ * Returns: True if at least one valid user-id is left over.
  */
 static int
-delete_inv_parts( const char *fname, kbnode_t keyblock,
-                 u32 *keyid, unsigned int options)
+delete_inv_parts (kbnode_t keyblock, u32 *keyid, unsigned int options)
 {
   kbnode_t node;
   int nvalid=0, uid_seen=0, subkey_seen=0;
 
-  (void)fname;
-
   for (node=keyblock->next; node; node = node->next )
     {
       if (node->pkt->pkttype == PKT_USER_ID)
         {
           uid_seen = 1;
-          if ((node->flag & 2) || !(node->flag & 1) )
+          if ((node->flag & NODE_BAD_SELFSIG)
+              || !(node->flag & NODE_GOOD_SELFSIG))
             {
               if (opt.verbose )
                 {
@@ -2198,7 +2480,8 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
       else if (   node->pkt->pkttype == PKT_PUBLIC_SUBKEY
                || node->pkt->pkttype == PKT_SECRET_SUBKEY )
         {
-          if ((node->flag & 2) || !(node->flag & 1) )
+          if ((node->flag & NODE_BAD_SELFSIG)
+              || !(node->flag & NODE_GOOD_SELFSIG))
             {
               if (opt.verbose )
                 log_info( _("key %s: skipped subkey\n"),keystr(keyid));
@@ -2286,7 +2569,7 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
                      node->pkt->pkt.signature->sig_class);
           delete_kbnode(node);
          }
-      else if ((node->flag & 4) ) /* marked for deletion */
+      else if ((node->flag & NODE_DELETION_MARK))
         delete_kbnode( node );
     }
 
@@ -2513,10 +2796,10 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
  *   the signature's public key yet; verification is done when putting it
  *   into the trustdb, which is done automagically as soon as this pubkey
  *   is used.
- * Note: We indicate newly inserted packets with flag bit 0
+ * Note: We indicate newly inserted packets with NODE_FLAG_A.
  */
 static int
-merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
+merge_blocks (kbnode_t keyblock_orig, kbnode_t keyblock,
              u32 *keyid, int *n_uids, int *n_sigs, int *n_subk )
 {
   kbnode_t onode, node;
@@ -2549,7 +2832,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
             {
               kbnode_t n2 = clone_kbnode(node);
               insert_kbnode( keyblock_orig, n2, 0 );
-              n2->flag |= 1;
+              n2->flag |= NODE_FLAG_A;
               ++*n_sigs;
               if(!opt.quiet)
                 {
@@ -2589,7 +2872,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
             {
               kbnode_t n2 = clone_kbnode(node);
               insert_kbnode( keyblock_orig, n2, 0 );
-              n2->flag |= 1;
+              n2->flag |= NODE_FLAG_A;
               ++*n_sigs;
               if(!opt.quiet)
                 log_info( _("key %s: direct key signature added\n"),
@@ -2601,7 +2884,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
   /* 3rd: try to merge new certificates in */
   for (onode=keyblock_orig->next; onode; onode=onode->next)
     {
-      if (!(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID)
+      if (!(onode->flag & NODE_FLAG_A) && onode->pkt->pkttype == PKT_USER_ID)
         {
           /* find the user id in the imported keyblock */
           for (node=keyblock->next; node; node=node->next)
@@ -2611,7 +2894,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (node ) /* found: merge */
             {
-              rc = merge_sigs( onode, node, n_sigs, fname, keyid );
+              rc = merge_sigs (onode, node, n_sigs);
               if (rc )
                 return rc;
            }
@@ -2631,7 +2914,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (!onode ) /* this is a new user id: append */
             {
-              rc = append_uid( keyblock_orig, node, n_sigs, fname, keyid);
+              rc = append_uid (keyblock_orig, node, n_sigs);
               if (rc )
                 return rc;
               ++*n_uids;
@@ -2653,7 +2936,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (!onode ) /* This is a new subkey: append.  */
             {
-              rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
+              rc = append_key (keyblock_orig, node, n_sigs);
               if (rc)
                 return rc;
               ++*n_subk;
@@ -2669,7 +2952,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (!onode ) /* This is a new subkey: append.  */
             {
-              rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
+              rc = append_key (keyblock_orig, node, n_sigs);
               if (rc )
                 return rc;
               ++*n_subk;
@@ -2680,7 +2963,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
   /* 6th: merge subkey certificates */
   for (onode=keyblock_orig->next; onode; onode=onode->next)
     {
-      if (!(onode->flag & 1)
+      if (!(onode->flag & NODE_FLAG_A)
           && (onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
               || onode->pkt->pkttype == PKT_SECRET_SUBKEY))
         {
@@ -2695,7 +2978,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
            }
           if (node) /* Found: merge.  */
             {
-              rc = merge_keysigs( onode, node, n_sigs, fname, keyid );
+              rc = merge_keysigs( onode, node, n_sigs);
               if (rc )
                 return rc;
            }
@@ -2706,19 +2989,15 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
 }
 
 
-/*
+/* Helper function for merge_blocks.
  * Append the userid starting with NODE and all signatures to KEYBLOCK.
  */
 static int
-append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-            const char *fname, u32 *keyid )
+append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs)
 {
   kbnode_t n;
   kbnode_t n_where = NULL;
 
-  (void)fname;
-  (void)keyid;
-
   log_assert (node->pkt->pkttype == PKT_USER_ID );
 
   /* find the position */
@@ -2744,8 +3023,8 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
        }
       else
         add_kbnode( keyblock, n );
-      n->flag |= 1;
-      node->flag |= 1;
+      n->flag |= NODE_FLAG_A;
+      node->flag |= NODE_FLAG_A;
       if (n->pkt->pkttype == PKT_SIGNATURE )
         ++*n_sigs;
 
@@ -2758,20 +3037,16 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
 }
 
 
-/*
+/* Helper function for merge_blocks
  * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID.
  * (how should we handle comment packets here?)
  */
 static int
-merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-            const char *fname, u32 *keyid)
+merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs)
 {
   kbnode_t n, n2;
   int found = 0;
 
-  (void)fname;
-  (void)keyid;
-
   log_assert (dst->pkt->pkttype == PKT_USER_ID);
   log_assert (src->pkt->pkttype == PKT_USER_ID);
 
@@ -2797,8 +3072,8 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
            * one is released first */
           n2 = clone_kbnode(n);
           insert_kbnode( dst, n2, PKT_SIGNATURE );
-          n2->flag |= 1;
-          n->flag |= 1;
+          n2->flag |= NODE_FLAG_A;
+          n->flag |= NODE_FLAG_A;
           ++*n_sigs;
        }
     }
@@ -2807,19 +3082,15 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
 }
 
 
-/*
+/* Helper function for merge_blocks
  * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY.
  */
 static int
-merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-               const char *fname, u32 *keyid)
+merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs)
 {
   kbnode_t n, n2;
   int found = 0;
 
-  (void)fname;
-  (void)keyid;
-
   log_assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
               || dst->pkt->pkttype == PKT_SECRET_SUBKEY);
 
@@ -2858,8 +3129,8 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
            * one is released first */
           n2 = clone_kbnode(n);
           insert_kbnode( dst, n2, PKT_SIGNATURE );
-          n2->flag |= 1;
-          n->flag |= 1;
+          n2->flag |= NODE_FLAG_A;
+          n->flag |= NODE_FLAG_A;
           ++*n_sigs;
        }
     }
@@ -2868,19 +3139,15 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
 }
 
 
-/*
+/* Helper function for merge_blocks.
  * Append the subkey starting with NODE and all signatures to KEYBLOCK.
  * Mark all new and copied packets by setting flag bit 0.
  */
 static int
-append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-            const char *fname, u32 *keyid)
+append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs)
 {
   kbnode_t n;
 
-  (void)fname;
-  (void)keyid;
-
   log_assert (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
               || node->pkt->pkttype == PKT_SECRET_SUBKEY);
 
@@ -2890,8 +3157,8 @@ append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
        * one is released first */
       n = clone_kbnode(node);
       add_kbnode( keyblock, n );
-      n->flag |= 1;
-      node->flag |= 1;
+      n->flag |= NODE_FLAG_A;
+      node->flag |= NODE_FLAG_A;
       if (n->pkt->pkttype == PKT_SIGNATURE )
         ++*n_sigs;
 
index a1d1f3d..e814fa8 100644 (file)
 static int cleanup_registered;
 static KBNODE unused_nodes;
 
-#if USE_UNUSED_NODES
 static void
 release_unused_nodes (void)
 {
+#if USE_UNUSED_NODES
   while (unused_nodes)
     {
       kbnode_t next = unused_nodes->next;
       xfree (unused_nodes);
       unused_nodes = next;
     }
-}
 #endif /*USE_UNUSED_NODES*/
+}
 
 
 static kbnode_t
index 17ddd5d..e49e25f 100644 (file)
@@ -937,6 +937,7 @@ keydb_release (KEYDB_HANDLE hd)
         }
     }
 
+  keyblock_cache_clear (hd);
   xfree (hd);
 }
 
index a30cf7a..4e8f3f2 100644 (file)
@@ -70,15 +70,16 @@ enum resource_type {
 /* Bit flags used with build_pk_list.  */
 enum
   {
-    PK_LIST_ENCRYPT_TO=1,   /* This is an encrypt-to recipient.  */
-    PK_LIST_HIDDEN=2,       /* This is a hidden recipient.       */
-    PK_LIST_CONFIG=4        /* Specified via config file.        */
+    PK_LIST_ENCRYPT_TO = 1, /* This is an encrypt-to recipient.    */
+    PK_LIST_HIDDEN     = 2, /* This is a hidden recipient.         */
+    PK_LIST_CONFIG     = 4, /* Specified via config file.          */
+    PK_LIST_FROM_FILE  = 8  /* Take key from file with that name.  */
   };
-/* To store private data in the flags they must be left shifted by
-   this value.  */
+/* To store private data in the flags the private data must be left
+   shifted by this value.  */
 enum
   {
-    PK_LIST_SHIFT=3
+    PK_LIST_SHIFT = 4
   };
 
 /****************
@@ -104,7 +105,7 @@ struct pk_list
 {
   PK_LIST next;
   PKT_public_key *pk;
-  int flags; /* flag bit 1==throw_keyid */
+  int flags;           /* See PK_LIST_ constants. */
 };
 
 /* Structure to hold a list of secret key certificates.  */
@@ -228,7 +229,8 @@ void release_pk_list (PK_LIST pk_list);
 int  build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
 gpg_error_t find_and_check_key (ctrl_t ctrl,
                                 const char *name, unsigned int use,
-                                int mark_hidden, pk_list_t *pk_list_addr);
+                                int mark_hidden, int from_file,
+                                pk_list_t *pk_list_addr);
 
 int  algo_available( preftype_t preftype, int algo,
                     const union pref_hint *hint );
@@ -322,6 +324,10 @@ int get_pubkey_byname (ctrl_t ctrl,
                        KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
                       int include_unusable, int no_akl );
 
+/* Get a public key directly from file FNAME.  */
+gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
+                                 PKT_public_key *pk, const char *fname);
+
 /* Return the public key with the key id KEYID iff the secret key is
  * available and store it at PK.  */
 gpg_error_t get_seckey (PKT_public_key *pk, u32 *keyid);
index d05ea5d..9ebd643 100644 (file)
@@ -87,6 +87,9 @@ static int real_uids_left (KBNODE keyblock);
 static int count_selected_keys (KBNODE keyblock);
 static int menu_revsig (KBNODE keyblock);
 static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock);
+static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+                        const struct revocation_reason_info *reason,
+                        int *modified);
 static int menu_revkey (KBNODE pub_keyblock);
 static int menu_revsubkey (KBNODE pub_keyblock);
 #ifndef NO_TRUST_MODELS
@@ -2937,6 +2940,110 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
   keydb_release (kdbhd);
 }
 
+/* Unattended revokation of a keyid.  USERNAME specifies the
+   key. UIDTOREV is the user id revoke from the key.  */
+void
+keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE kdbhd = NULL;
+  KEYDB_SEARCH_DESC desc;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
+  int modified = 0;
+  size_t revlen;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* Search the key; we don't want the whole getkey stuff here.  */
+  kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      /* Note that keydb_new has already used log_error.  */
+      goto leave;
+    }
+
+  err = classify_user_id (username, &desc, 1);
+  if (!err)
+    err = keydb_search (kdbhd, &desc, 1, NULL);
+  if (!err)
+    {
+      err = keydb_get_keyblock (kdbhd, &keyblock);
+      if (err)
+        {
+          log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+      /* Now with the keyblock retrieved, search again to detect an
+         ambiguous specification.  We need to save the found state so
+         that we can do an update later.  */
+      keydb_push_found_state (kdbhd);
+      err = keydb_search (kdbhd, &desc, 1, NULL);
+      if (!err)
+        err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+      else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+        err = 0;
+      keydb_pop_found_state (kdbhd);
+
+      if (!err)
+        {
+          /* We require the secret primary key to revoke a UID.  */
+          node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
+          if (!node)
+            BUG ();
+          err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
+        }
+    }
+  if (err)
+    {
+      log_error (_("secret key \"%s\" not found: %s\n"),
+                 username, gpg_strerror (err));
+      goto leave;
+    }
+
+  fix_keyblock (&keyblock);
+  setup_main_keyids (keyblock);
+
+  revlen = strlen (uidtorev);
+  /* find the right UID */
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_USER_ID
+          && revlen == node->pkt->pkt.user_id->len
+          && !memcmp (node->pkt->pkt.user_id->name, uidtorev, revlen))
+        {
+          struct revocation_reason_info *reason;
+
+          reason = get_default_uid_revocation_reason ();
+          err = core_revuid (ctrl, keyblock, node, reason, &modified);
+          release_revocation_reason_info (reason);
+          if (err)
+            {
+              log_error (_("User ID revocation failed: %s\n"),
+                         gpg_strerror (err));
+              goto leave;
+            }
+          err = keydb_update_keyblock (kdbhd, keyblock);
+          if (err)
+            {
+              log_error (_("update failed: %s\n"), gpg_strerror (err));
+              goto leave;
+            }
+
+          if (update_trust)
+            revalidation_mark ();
+          goto leave;
+        }
+    }
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
 
 /* Find a keyblock by fingerprint because only this uniquely
  * identifies a key and may thus be used to select a key for
@@ -6106,6 +6213,95 @@ reloop:                  /* (must use this, because we are modifing the list) */
 }
 
 
+/* return 0 if revocation of NODE (which must be a User ID) was
+   successful, non-zero if there was an error.  *modified will be set
+   to 1 if a change was made. */
+static int
+core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+             const struct revocation_reason_info *reason, int *modified)
+{
+  PKT_public_key *pk = keyblock->pkt->pkt.public_key;
+  gpg_error_t rc;
+
+  if (node->pkt->pkttype != PKT_USER_ID)
+    {
+      rc = gpg_error (GPG_ERR_NO_USER_ID);
+      write_status_error ("keysig", rc);
+      log_error (_("tried to revoke a non-user ID: %s\n"), gpg_strerror (rc));
+      return 1;
+    }
+  else
+    {
+      PKT_user_id *uid = node->pkt->pkt.user_id;
+
+      if (uid->is_revoked)
+        {
+          char *user = utf8_to_native (uid->name, uid->len, 0);
+          log_info (_("user ID \"%s\" is already revoked\n"), user);
+          xfree (user);
+        }
+      else
+        {
+          PACKET *pkt;
+          PKT_signature *sig;
+          struct sign_attrib attrib;
+          u32 timestamp = make_timestamp ();
+
+          if (uid->created >= timestamp)
+            {
+              /* Okay, this is a problem.  The user ID selfsig was
+                 created in the future, so we need to warn the user and
+                 set our revocation timestamp one second after that so
+                 everything comes out clean. */
+
+              log_info (_("WARNING: a user ID signature is dated %d"
+                          " seconds in the future\n"),
+                        uid->created - timestamp);
+
+              timestamp = uid->created + 1;
+            }
+
+          memset (&attrib, 0, sizeof attrib);
+          /* should not need to cast away const here; but
+             revocation_reason_build_cb needs to take a non-const
+             void* in order to meet the function signtuare for the
+             mksubpkt argument to make_keysig_packet */
+          attrib.reason = (struct revocation_reason_info *)reason;
+
+          rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
+                                   timestamp, 0,
+                                   sign_mk_attrib, &attrib, NULL);
+          if (rc)
+            {
+              write_status_error ("keysig", rc);
+              log_error (_("signing failed: %s\n"), gpg_strerror (rc));
+              return 1;
+            }
+          else
+            {
+              pkt = xmalloc_clear (sizeof *pkt);
+              pkt->pkttype = PKT_SIGNATURE;
+              pkt->pkt.signature = sig;
+              insert_kbnode (node, new_kbnode (pkt), 0);
+
+#ifndef NO_TRUST_MODELS
+              /* If the trustdb has an entry for this key+uid then the
+                 trustdb needs an update. */
+              if (!update_trust
+                  && ((get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK)
+                      >= TRUST_UNDEFINED))
+                update_trust = 1;
+#endif /*!NO_TRUST_MODELS*/
+
+              node->pkt->pkt.user_id->is_revoked = 1;
+              if (modified)
+                *modified = 1;
+            }
+        }
+      return 0;
+    }
+}
+
 /* Revoke a user ID (i.e. revoke a user ID selfsig).  Return true if
    keyblock changed.  */
 static int
@@ -6132,75 +6328,20 @@ menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock)
          goto leave;
       }
 
- reloop: /* (better this way because we are modifing the keyring) */
+ reloop: /* (better this way because we are modifying the keyring) */
   for (node = pub_keyblock; node; node = node->next)
     if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
       {
-       PKT_user_id *uid = node->pkt->pkt.user_id;
-
-       if (uid->is_revoked)
-         {
-           char *user = utf8_to_native (uid->name, uid->len, 0);
-           log_info (_("user ID \"%s\" is already revoked\n"), user);
-           xfree (user);
-         }
-       else
-         {
-           PACKET *pkt;
-           PKT_signature *sig;
-           struct sign_attrib attrib;
-           u32 timestamp = make_timestamp ();
-
-           if (uid->created >= timestamp)
-             {
-               /* Okay, this is a problem.  The user ID selfsig was
-                  created in the future, so we need to warn the user and
-                  set our revocation timestamp one second after that so
-                  everything comes out clean. */
-
-               log_info (_("WARNING: a user ID signature is dated %d"
-                           " seconds in the future\n"),
-                         uid->created - timestamp);
-
-               timestamp = uid->created + 1;
-             }
-
-           memset (&attrib, 0, sizeof attrib);
-           attrib.reason = reason;
-
+        int modified = 0;
+        rc = core_revuid (ctrl, pub_keyblock, node, reason, &modified);
+        if (rc)
+          goto leave;
+        if (modified)
+          {
            node->flag &= ~NODFLG_SELUID;
-
-           rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
-                                    timestamp, 0,
-                                    sign_mk_attrib, &attrib, NULL);
-           if (rc)
-             {
-                write_status_error ("keysig", rc);
-               log_error (_("signing failed: %s\n"), gpg_strerror (rc));
-               goto leave;
-             }
-           else
-             {
-               pkt = xmalloc_clear (sizeof *pkt);
-               pkt->pkttype = PKT_SIGNATURE;
-               pkt->pkt.signature = sig;
-               insert_kbnode (node, new_kbnode (pkt), 0);
-
-#ifndef NO_TRUST_MODELS
-               /* If the trustdb has an entry for this key+uid then the
-                  trustdb needs an update. */
-               if (!update_trust
-                   && (get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK) >=
-                   TRUST_UNDEFINED)
-                 update_trust = 1;
-#endif /*!NO_TRUST_MODELS*/
-
-               changed = 1;
-               node->pkt->pkt.user_id->is_revoked = 1;
-
-               goto reloop;
-             }
-         }
+            changed = 1;
+            goto reloop;
+          }
       }
 
   if (changed)
index 74fd370..2b3d328 100644 (file)
@@ -202,7 +202,7 @@ write_uid( KBNODE root, const char *s )
     size_t n = strlen(s);
 
     pkt->pkttype = PKT_USER_ID;
-    pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
+    pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
     pkt->pkt.user_id->len = n;
     pkt->pkt.user_id->ref = 1;
     strcpy(pkt->pkt.user_id->name, s);
@@ -413,9 +413,9 @@ keygen_set_std_prefs (const char *string,int personal)
 
     if(strlen(string))
       {
-       char *tok,*prefstring;
+       char *dup, *tok, *prefstring;
 
-       prefstring=xstrdup(string); /* need a writable string! */
+       dup = prefstring = xstrdup (string); /* need a writable string! */
 
        while((tok=strsep(&prefstring," ,")))
          {
@@ -449,7 +449,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
          }
 
-       xfree(prefstring);
+       xfree (dup);
       }
 
     if(!rc)
@@ -3481,6 +3481,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
        xfree( outctrl.pub.newfname );
     }
 
+    xfree (line);
     release_parameter_list( para );
     iobuf_close (fp);
     release_armor_context (outctrl.pub.afx);
@@ -3610,7 +3611,13 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
       }
   }
 
-  if (*algostr || *usagestr || *expirestr)
+
+  if (!strcmp (algostr, "test-default"))
+    {
+      para = quickgen_set_para (para, 0, PUBKEY_ALGO_EDDSA, 0, "Ed25519", 0);
+      para = quickgen_set_para (para, 1, PUBKEY_ALGO_ECDH,  0, "Curve25519", 0);
+    }
+  else if (*algostr || *usagestr || *expirestr)
     {
       /* Extended unattended mode.  Creates only the primary key. */
       int algo;
@@ -4340,11 +4347,15 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
 
           gen_standard_revoke (pk, cache_nonce);
 
+          /* Get rid of the first empty packet.  */
+          commit_kbnode (&pub_root);
+
           if (!opt.batch)
             {
               tty_printf (_("public and secret key created and signed.\n") );
               tty_printf ("\n");
-              list_keyblock_direct (ctrl, pub_root, 0, 1, 1);
+              merge_keys_and_selfsig (pub_root);
+              list_keyblock_direct (ctrl, pub_root, 0, 1, 1, 1);
             }
 
 
index e67f67f..84990a3 100644 (file)
@@ -347,11 +347,7 @@ format_keyid (u32 *keyid, int format, char *buffer, int len)
       break;
 
     case KF_LONG:
-      if (keyid[0])
-       snprintf (buffer, len, "%08lX%08lX",
-                  (ulong)keyid[0], (ulong)keyid[1]);
-      else
-       snprintf (buffer, len, "%08lX", (ulong)keyid[1]);
+      snprintf (buffer, len, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1]);
       break;
 
     case KF_0xSHORT:
@@ -359,11 +355,7 @@ format_keyid (u32 *keyid, int format, char *buffer, int len)
       break;
 
     case KF_0xLONG:
-      if(keyid[0])
-       snprintf (buffer, len, "0x%08lX%08lX",
-                  (ulong)keyid[0],(ulong)keyid[1]);
-      else
-       snprintf (buffer, len, "0x%08lX", (ulong)keyid[1]);
+      snprintf (buffer, len, "0x%08lX%08lX", (ulong)keyid[0],(ulong)keyid[1]);
       break;
 
     default:
index 0ac763d..2c99502 100644 (file)
@@ -59,6 +59,7 @@ struct keylist_context
   int inv_sigs;    /* Counter used if CHECK_SIGS is set.  */
   int no_key;      /* Counter used if CHECK_SIGS is set.  */
   int oth_err;     /* Counter used if CHECK_SIGS is set.  */
+  int no_validity; /* Do not show validity.  */
 };
 
 
@@ -863,156 +864,6 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
 }
 
 
-/* Print IPGP cert records instead of a standard key listing.  */
-static void
-list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
-{
-  kbnode_t kbctx;
-  kbnode_t node;
-  PKT_public_key *pk;
-  char pkstrbuf[PUBKEY_STRING_SIZE];
-  char *hexfpr;
-  char *hexkeyblock = NULL;
-  unsigned int hexkeyblocklen = 0;  /* Init to avoid -Wmaybe-uninitialized. */
-  const char *s;
-
-  /* Get the keyid from the keyblock.  */
-  node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
-  if (!node)
-    {
-      log_error ("Oops; key lost!\n");
-      dump_kbnode (keyblock);
-      return;
-    }
-
-  pk = node->pkt->pkt.public_key;
-
-  /* First print an overview of the key with all userids.  */
-  es_fprintf (es_stdout, ";; pub  %s/%s %s\n;;",
-              pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
-              keystr_from_pk (pk), datestr_from_pk (pk));
-  print_fingerprint (NULL, pk, 10);
-  for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
-    {
-      if (node->pkt->pkttype == PKT_USER_ID)
-       {
-         PKT_user_id *uid = node->pkt->pkt.user_id;
-
-         if (pk && (uid->is_expired || uid->is_revoked)
-             && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
-            continue;
-
-          es_fputs (";; uid  ", es_stdout);
-          print_utf8_buffer (es_stdout, uid->name, uid->len);
-          es_putc ('\n', es_stdout);
-        }
-    }
-
-
-  hexfpr = hexfingerprint (pk, NULL, 0);
-  if (opt.print_dane_records)
-    {
-      kbnode_t dummy_keyblock;
-      void *data;
-      size_t datalen;
-      gpg_error_t err;
-
-      /* We do not have an export function which allows to pass a
-         keyblock, thus we need to search the key again.  */
-      err = export_pubkey_buffer (ctrl, hexfpr,
-                                  EXPORT_DANE_FORMAT, NULL,
-                                  &dummy_keyblock, &data, &datalen);
-      release_kbnode (dummy_keyblock);
-      if (!err)
-        {
-          hexkeyblocklen = datalen;
-          hexkeyblock = bin2hex (data, datalen, NULL);
-          if (!hexkeyblock)
-            err = gpg_error_from_syserror ();
-          xfree (data);
-          ascii_strlwr (hexkeyblock);
-        }
-      if (err)
-        log_error (_("skipped \"%s\": %s\n"), hexfpr, gpg_strerror (err));
-
-    }
-
-  for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
-    {
-      if (node->pkt->pkttype == PKT_USER_ID)
-       {
-         PKT_user_id *uid = node->pkt->pkt.user_id;
-          char *mbox;
-          char *p;
-
-         if (pk && (uid->is_expired || uid->is_revoked)
-             && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
-            continue;
-
-          mbox = mailbox_from_userid (uid->name);
-          if (mbox && (p = strchr (mbox, '@')))
-            {
-              char hashbuf[32];
-              char *hash;
-              unsigned int len;
-
-              *p++ = 0;
-              if (opt.print_pka_records)
-                {
-                  es_fprintf (es_stdout, "$ORIGIN _pka.%s.\n; %s\n; ",
-                              p, hexfpr);
-                  print_utf8_buffer (es_stdout, uid->name, uid->len);
-                  es_putc ('\n', es_stdout);
-                  gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf,
-                                       mbox, strlen (mbox));
-                  hash = zb32_encode (hashbuf, 8*20);
-                  if (hash)
-                    {
-                      len = strlen (hexfpr)/2;
-                      es_fprintf (es_stdout,
-                                  "%s TYPE37 \\# %u 0006 0000 00 %02X %s\n",
-                                  hash, 6 + len, len, hexfpr);
-                      xfree (hash);
-                    }
-                }
-              if (opt.print_dane_records && hexkeyblock)
-                {
-                  es_fprintf (es_stdout, "$ORIGIN _openpgpkey.%s.\n; %s\n; ",
-                              p, hexfpr);
-                  print_utf8_buffer (es_stdout, uid->name, uid->len);
-                  es_putc ('\n', es_stdout);
-                  gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf,
-                                       mbox, strlen (mbox));
-                  hash = bin2hex (hashbuf, 28, NULL);
-                  if (hash)
-                    {
-                      ascii_strlwr (hash);
-                      es_fprintf (es_stdout, "%s TYPE61 \\# %u (\n",
-                                  hash, hexkeyblocklen);
-                      xfree (hash);
-                      s = hexkeyblock;
-                      for (;;)
-                        {
-                          es_fprintf (es_stdout, "\t%.64s\n", s);
-                          if (strlen (s) < 64)
-                            break;
-                          s += 64;
-                        }
-                      es_fputs ("\t)\n", es_stdout);
-                    }
-                }
-            }
-          xfree (mbox);
-       }
-
-    }
-  es_putc ('\n', es_stdout);
-
-  xfree (hexkeyblock);
-  xfree (hexfpr);
-}
-
-
 static void
 list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
                      struct keylist_context *listctx)
@@ -1052,7 +903,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
         secret = 2;  /* Key not found.  */
     }
 
-  check_trustdb_stale (ctrl);
+  if (!listctx->no_validity)
+    check_trustdb_stale (ctrl);
 
   /* Print the "pub" line and in KF_NONE mode the fingerprint.  */
   print_key_line (es_stdout, pk, secret);
@@ -1090,7 +942,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
            dump_attribs (uid, pk);
 
          if ((uid->is_revoked || uid->is_expired)
-             || (opt.list_options & LIST_SHOW_UID_VALIDITY))
+             || ((opt.list_options & LIST_SHOW_UID_VALIDITY)
+                  && !listctx->no_validity))
            {
              const char *validity;
 
@@ -1744,25 +1597,28 @@ list_keyblock (ctrl_t ctrl,
                struct keylist_context *listctx)
 {
   reorder_keyblock (keyblock);
-  if (opt.print_pka_records || opt.print_dane_records)
-    list_keyblock_pka (ctrl, keyblock);
-  else if (opt.with_colons)
+
+  if (opt.with_colons)
     list_keyblock_colon (ctrl, keyblock, secret, has_secret, fpr);
   else
     list_keyblock_print (ctrl, keyblock, secret, fpr, listctx);
+
   if (secret)
     es_fflush (es_stdout);
 }
 
 
-/* Public function used by keygen to list a keyblock.  */
+/* Public function used by keygen to list a keyblock.  If NO_VALIDITY
+ * is set the validity of a key is never shown.  */
 void
 list_keyblock_direct (ctrl_t ctrl,
-                      kbnode_t keyblock, int secret, int has_secret, int fpr)
+                      kbnode_t keyblock, int secret, int has_secret, int fpr,
+                      int no_validity)
 {
   struct keylist_context listctx;
 
   memset (&listctx, 0, sizeof (listctx));
+  listctx.no_validity = !!no_validity;
   list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx);
   keylist_context_release (&listctx);
 }
index d7105de..2e2d6a4 100644 (file)
@@ -240,13 +240,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
   struct keyserver_spec *keyserver;
   const char *idx;
   int count;
-  char *uri,*options;
+  char *uri, *duped_uri, *options;
 
   log_assert (string);
 
   keyserver=xmalloc_clear(sizeof(struct keyserver_spec));
 
-  uri=xstrdup(string);
+  duped_uri = uri = xstrdup (string);
 
   options=strchr(uri,' ');
   if(options)
@@ -434,11 +434,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
       goto fail;
     }
 
+  xfree (duped_uri);
   return keyserver;
 
  fail:
   free_keyserver_spec(keyserver);
 
+  xfree (duped_uri);
   return NULL;
 }
 
index 7b716ff..0956f66 100644 (file)
@@ -289,6 +289,8 @@ void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
                            const char *newuid);
 void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
                            const char *usagestr, const char *expirestr);
+void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
+                           const char *uidtorev);
 void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
                          strlist_t uids, strlist_t locusr, int local);
 void show_basic_key_info (KBNODE keyblock);
@@ -347,6 +349,9 @@ typedef struct import_stats_s *import_stats_t;
 typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg);
 
 int parse_import_options(char *str,unsigned int *options,int noisy);
+gpg_error_t parse_and_set_import_filter (const char *string);
+gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname,
+                                kbnode_t *r_keyblock);
 void import_keys (ctrl_t ctrl, char **fnames, int nnames,
                  import_stats_t stats_hd, unsigned int options);
 int import_keys_stream (ctrl_t ctrl, iobuf_t inp, import_stats_t stats_hd,
@@ -376,6 +381,7 @@ void export_release_stats (export_stats_t stats);
 void export_print_stats (export_stats_t stats);
 
 int parse_export_options(char *str,unsigned int *options,int noisy);
+gpg_error_t parse_and_set_export_filter (const char *string);
 
 int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
                     export_stats_t stats);
@@ -390,9 +396,13 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
 
 gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
                                        int cleartext,
-                                       char **cache_nonce_addr, const char *hexgrip,
+                                       char **cache_nonce_addr,
+                                       const char *hexgrip,
                                        PKT_public_key *pk);
 
+gpg_error_t write_keyblock_to_output (kbnode_t keyblock,
+                                      int with_armor, unsigned int options);
+
 gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid);
 
 /*-- dearmor.c --*/
@@ -407,6 +417,7 @@ int gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr);
 int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
 struct revocation_reason_info *
                ask_revocation_reason( int key_rev, int cert_rev, int hint );
+struct revocation_reason_info * get_default_uid_revocation_reason(void);
 void release_revocation_reason_info( struct revocation_reason_info *reason );
 
 /*-- keylist.c --*/
@@ -415,7 +426,7 @@ void secret_key_list (ctrl_t ctrl, strlist_t list );
 void print_subpackets_colon(PKT_signature *sig);
 void reorder_keyblock (KBNODE keyblock);
 void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
-                           int has_secret, int fpr);
+                           int has_secret, int fpr, int no_validity);
 void print_fingerprint (estream_t fp, PKT_public_key *pk, int mode);
 void print_revokers (estream_t fp, PKT_public_key *pk);
 void show_policy_url(PKT_signature *sig,int indent,int mode);
index 453d1b0..4217ccd 100644 (file)
@@ -124,8 +124,6 @@ reset_literals_seen(void)
 static void
 release_list( CTX c )
 {
-  if (!c->list)
-    return;
   proc_tree (c, c->list);
   release_kbnode (c->list);
   while (c->pkenc_list)
@@ -1328,7 +1326,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
           /* Stop processing when an invalid packet has been encountered
            * but don't do so when we are doing a --list-packets.  */
           if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
-              && opt.list_packets != 2 )
+              && opt.list_packets == 0)
             break;
           continue;
        }
@@ -1805,19 +1803,26 @@ check_sig_and_print (CTX c, kbnode_t node)
    * favor this over the WKD method (to be tried next), because an
    * arbitrary keyserver is less subject to web bug like
    * monitoring.  */
-  /* if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY */
-  /*     && signature_hash_full_fingerprint (sig) */
-  /*     && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) */
-  /*     && keyserver_any_configured (c->ctrl)) */
-  /*   { */
-  /*     int res; */
-
-  /*     glo_ctrl.in_auto_key_retrieve++; */
-  /*     res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); */
-  /*     glo_ctrl.in_auto_key_retrieve--; */
-  /*     if (!res) */
-  /*       rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); */
-  /*   } */
+  if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
+      && opt.flags.rfc4880bis
+      && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
+      && keyserver_any_configured (c->ctrl))
+    {
+      int res;
+      const byte *p;
+      size_t n;
+
+      p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
+      if (p && n == 21 && p[0] == 4)
+        {
+          /* v4 packet with a SHA-1 fingerprint.  */
+          glo_ctrl.in_auto_key_retrieve++;
+          res = keyserver_import_fprint (c->ctrl, p+1, n-1, opt.keyserver);
+          glo_ctrl.in_auto_key_retrieve--;
+          if (!res)
+            rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+        }
+    }
 
   /* If the above methods didn't work, our next try is to retrieve the
    * key from the WKD. */
index 0a87b90..ccd8acb 100644 (file)
@@ -57,6 +57,7 @@ struct
   int dry_run;
   int autostart;
   int list_only;
+  int mimemode;
   int textmode;
   int expert;
   const char *def_sig_expire;
@@ -77,10 +78,8 @@ struct
   int with_wkd_hash;    /* Option --with-wkd-hash.  */
   int fingerprint; /* list fingerprints */
   int list_sigs;   /* list signatures */
-  int print_pka_records;
-  int print_dane_records;
   int no_armor;
-  int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
+  int list_packets; /* Option --list-packets active.  */
   int def_cipher_algo;
   int force_mdc;
   int disable_mdc;
@@ -235,6 +234,8 @@ struct
     unsigned int allow_weak_digest_algos:1;
     unsigned int large_rsa:1;
     unsigned int disable_signer_uid:1;
+    /* Flag to enbale experimental features from RFC4880bis.  */
+    unsigned int rfc4880bis:1;
   } flags;
 
   /* Linked list of ways to find a key if the key isn't on the local
@@ -332,11 +333,13 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
 #define IMPORT_LOCAL_SIGS                (1<<0)
 #define IMPORT_REPAIR_PKS_SUBKEY_BUG     (1<<1)
 #define IMPORT_FAST                      (1<<2)
+#define IMPORT_SHOW                      (1<<3)
 #define IMPORT_MERGE_ONLY                (1<<4)
 #define IMPORT_MINIMAL                   (1<<5)
 #define IMPORT_CLEAN                     (1<<6)
 #define IMPORT_NO_SECKEY                 (1<<7)
 #define IMPORT_KEEP_OWNERTTRUST          (1<<8)
+#define IMPORT_EXPORT                    (1<<9)
 
 #define EXPORT_LOCAL_SIGS                (1<<0)
 #define EXPORT_ATTRIBUTES                (1<<1)
@@ -344,7 +347,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
 #define EXPORT_RESET_SUBKEY_PASSWD       (1<<3)
 #define EXPORT_MINIMAL                   (1<<4)
 #define EXPORT_CLEAN                     (1<<5)
-#define EXPORT_DANE_FORMAT               (1<<6)
+#define EXPORT_PKA_FORMAT                (1<<6)
+#define EXPORT_DANE_FORMAT               (1<<7)
 
 #define LIST_SHOW_PHOTOS                 (1<<0)
 #define LIST_SHOW_POLICY_URLS            (1<<1)
index 8fb6fc4..08e2cb7 100644 (file)
@@ -291,9 +291,10 @@ typedef struct
     unsigned int ks_modify:1;
     unsigned int compacted:1;
   } flags;
+  char *mbox;   /* NULL or the result of mailbox_from_userid.  */
   /* The text contained in the user id packet, which is normally the
      name and email address of the key holder (See RFC 4880 5.11).
-     (Serialized.)  */
+     (Serialized.). For convenience an extra Nul is always appended.  */
   char name[1];
 } PKT_user_id;
 
@@ -764,7 +765,7 @@ gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
 u32 calc_packet_length( PACKET *pkt );
 void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
                        const byte *buffer, size_t buflen );
-void build_sig_subpkt_from_sig( PKT_signature *sig );
+void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk);
 int  delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
 void build_attribute_subpkt(PKT_user_id *uid,byte type,
                            const void *buf,u32 buflen,
index e02238b..ec8a641 100644 (file)
@@ -211,7 +211,7 @@ set_packet_list_mode (int mode)
      enable the list mode only with a special option. */
   if (!listfp)
     {
-      if (opt.list_packets == 2)
+      if (opt.list_packets)
         {
           listfp = es_stdout;
           if (opt.verbose)
@@ -1335,6 +1335,19 @@ dump_sig_subpkt (int hashed, int type, int critical,
                     (ulong) buf32_to_u32 (buffer),
                     (ulong) buf32_to_u32 (buffer + 4));
       break;
+    case SIGSUBPKT_ISSUER_FPR:
+      if (length >= 21)
+        {
+          char *tmp;
+          es_fprintf (listfp, "issuer fpr v%d ", buffer[0]);
+          tmp = bin2hex (buffer+1, length-1, NULL);
+          if (tmp)
+            {
+              es_fputs (tmp, listfp);
+              xfree (tmp);
+            }
+        }
+      break;
     case SIGSUBPKT_NOTATION:
       {
        es_fputs ("notation: ", listfp);
@@ -1485,6 +1498,10 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
       if (n < 8)
        break;
       return 0;
+    case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
+      if (n < 21)
+       break;
+      return 0;
     case SIGSUBPKT_NOTATION:
       /* minimum length needed, and the subpacket must be well-formed
          where the name length and value length all fit inside the
@@ -1543,6 +1560,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
     case SIGSUBPKT_REVOCABLE:
     case SIGSUBPKT_REV_KEY:
     case SIGSUBPKT_ISSUER:     /* issuer key ID */
+    case SIGSUBPKT_ISSUER_FPR: /* issuer fingerprint */
     case SIGSUBPKT_PREF_SYM:
     case SIGSUBPKT_PREF_HASH:
     case SIGSUBPKT_PREF_COMPR:
index 8efa954..6315a6d 100644 (file)
@@ -775,14 +775,16 @@ expand_id(const char *id,strlist_t *into,unsigned int flags)
 }
 
 /* For simplicity, and to avoid potential loops, we only expand once -
  you can't make an alias that points to an alias. */
* you can't make an alias that points to an alias.  */
 static strlist_t
-expand_group(strlist_t input)
+expand_group (strlist_t input)
 {
-  strlist_t sl,output=NULL,rover;
+  strlist_t output = NULL;
+  strlist_t sl, rover;
 
-  for(rover=input;rover;rover=rover->next)
-    if(expand_id(rover->d,&output,rover->flags)==0)
+  for (rover = input; rover; rover = rover->next)
+    if (!(rover->flags & PK_LIST_FROM_FILE)
+        && !expand_id(rover->d,&output,rover->flags))
       {
        /* Didn't find any groups, so use the existing string */
        sl=add_to_strlist(&output,rover->d);
@@ -794,17 +796,18 @@ expand_group(strlist_t input)
 
 
 /* Helper for build_pk_list to find and check one key.  This helper is
-   also used directly in server mode by the RECIPIENTS command.  On
-   success the new key is added to PK_LIST_ADDR.  NAME is the user id
-   of the key. USE the requested usage and a set MARK_HIDDEN will mark
-   the key in the updated list as a hidden recipient. */
+ * also used directly in server mode by the RECIPIENTS command.  On
+ * success the new key is added to PK_LIST_ADDR.  NAME is the user id
+ * of the key.  USE the requested usage and a set MARK_HIDDEN will
+ * mark the key in the updated list as a hidden recipient.  If
+ * FROM_FILE is true, NAME is is not a user ID but the name of a file
+ * holding a key. */
 gpg_error_t
 find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
-                    int mark_hidden, pk_list_t *pk_list_addr)
+                    int mark_hidden, int from_file, pk_list_t *pk_list_addr)
 {
   int rc;
   PKT_public_key *pk;
-  int trustlevel;
 
   if (!name || !*name)
     return gpg_error (GPG_ERR_INV_USER_ID);
@@ -814,7 +817,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     return gpg_error_from_syserror ();
   pk->req_usage = use;
 
-  rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
+  if (from_file)
+    rc = get_pubkey_fromfile (ctrl, pk, name);
+  else
+    rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
   if (rc)
     {
       int code;
@@ -844,24 +850,28 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     }
 
   /* Key found and usable.  Check validity. */
-  trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
-  if ( (trustlevel & TRUST_FLAG_DISABLED) )
+  if (!from_file)
     {
-      /* Key has been disabled. */
-      send_status_inv_recp (13, name);
-      log_info (_("%s: skipped: public key is disabled\n"), name);
-      free_public_key (pk);
-      return GPG_ERR_UNUSABLE_PUBKEY;
-    }
+      int trustlevel;
 
-  if ( !do_we_trust_pre (pk, trustlevel) )
-    {
-      /* We don't trust this key.  */
-      send_status_inv_recp (10, name);
-      free_public_key (pk);
-      return GPG_ERR_UNUSABLE_PUBKEY;
+      trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
+      if ( (trustlevel & TRUST_FLAG_DISABLED) )
+        {
+          /* Key has been disabled. */
+          send_status_inv_recp (13, name);
+          log_info (_("%s: skipped: public key is disabled\n"), name);
+          free_public_key (pk);
+          return GPG_ERR_UNUSABLE_PUBKEY;
+        }
+
+      if ( !do_we_trust_pre (pk, trustlevel) )
+        {
+          /* We don't trust this key.  */
+          send_status_inv_recp (10, name);
+          free_public_key (pk);
+          return GPG_ERR_UNUSABLE_PUBKEY;
+        }
     }
-  /* Note: do_we_trust may have changed the trustlevel. */
 
   /* Skip the actual key if the key is already present in the
      list.  */
@@ -894,22 +904,24 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
 
 
 /* This is the central function to collect the keys for recipients.
-   It is thus used to prepare a public key encryption. encrypt-to
-   keys, default keys and the keys for the actual recipients are all
-   collected here.  When not in batch mode and no recipient has been
-   passed on the commandline, the function will also ask for
-   recipients.
-
-   RCPTS is a string list with the recipients; NULL is an allowed
-   value but not very useful.  Group expansion is done on these names;
-   they may be in any of the user Id formats we can handle.  The flags
-   bits for each string in the string list are used for:
-     Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
-     Bit 1 (PK_LIST_HIDDEN)    : This is a hidden recipient.
-
-   On success a list of keys is stored at the address RET_PK_LIST; the
-   caller must free this list.  On error the value at this address is
-   not changed.
+ * It is thus used to prepare a public key encryption. encrypt-to
+ * keys, default keys and the keys for the actual recipients are all
+ * collected here.  When not in batch mode and no recipient has been
+ * passed on the commandline, the function will also ask for
+ * recipients.
+ *
+ * RCPTS is a string list with the recipients; NULL is an allowed
+ * value but not very useful.  Group expansion is done on these names;
+ * they may be in any of the user Id formats we can handle.  The flags
+ * bits for each string in the string list are used for:
+ *
+ * - PK_LIST_ENCRYPT_TO :: This is an encrypt-to recipient.
+ * - PK_LIST_HIDDEN     :: This is a hidden recipient.
+ * - PK_LIST_FROM_FILE  :: The argument is a file with a key.
+ *
+ * On success a list of keys is stored at the address RET_PK_LIST; the
+ * caller must free this list.  On error the value at this address is
+ * not changed.
  */
 int
 build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
@@ -1269,6 +1281,7 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
 
           rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
                                    !!(remusr->flags&PK_LIST_HIDDEN),
+                                   !!(remusr->flags&PK_LIST_FROM_FILE),
                                    &pk_list);
           if (rc)
             goto fail;
index e118f6b..c9fb67c 100644 (file)
@@ -217,11 +217,16 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
   static off_t count = 0;
   int err = 0;
   int c;
-  int convert = (pt->mode == 't' || pt->mode == 'u');
+  int convert;
 #ifdef __riscos__
   int filetype = 0xfff;
 #endif
 
+  if (pt->mode == 't' || pt->mode == 'u' || pt->mode == 'm')
+    convert = pt->mode;
+  else
+    convert = 0;
+
   /* Let people know what the plaintext info is. This allows the
      receiving program to try and do something different based on the
      format code (say, recode UTF-8 to local). */
@@ -279,8 +284,10 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
              if (mfx->md)
                gcry_md_putc (mfx->md, c);
 #ifndef HAVE_DOSISH_SYSTEM
-             if (c == '\r')    /* convert to native line ending */
-               continue;       /* fixme: this hack might be too simple */
+              /* Convert to native line ending. */
+              /* fixme: this hack might be too simple */
+             if (c == '\r' && convert != 'm')
+               continue;
 #endif
              if (fp)
                {
@@ -354,7 +361,7 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
              if (mfx->md)
                gcry_md_putc (mfx->md, c);
 #ifndef HAVE_DOSISH_SYSTEM
-             if (convert && c == '\r')
+             if (c == '\r' && convert != 'm')
                continue;       /* fixme: this hack might be too simple */
 #endif
              if (fp)
index 218ca59..15a91ac 100644 (file)
@@ -862,6 +862,16 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
     return reason;
 }
 
+struct revocation_reason_info *
+get_default_uid_revocation_reason(void)
+{
+  struct revocation_reason_info *reason;
+  reason = xmalloc( sizeof *reason );
+  reason->code = 0x20; /* uid is no longer valid */
+  reason->desc = strdup(""); /* no text */
+  return reason;
+}
+
 void
 release_revocation_reason_info( struct revocation_reason_info *reason )
 {
index 771a8a7..258f08a 100644 (file)
@@ -177,6 +177,7 @@ output_notify (assuan_context_t ctx, char *line)
 
 \f
 /*  RECIPIENT [--hidden] <userID>
+    RECIPIENT [--hidden] --file <filename>
 
    Set the recipient for the encryption.  <userID> should be the
    internal representation of the key; the server may accept any other
@@ -192,9 +193,10 @@ cmd_recipient (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
-  int hidden;
+  int hidden, file;
 
   hidden = has_option (line,"--hidden");
+  file = has_option (line,"--file");
   line = skip_options (line);
 
   /* FIXME: Expand groups
@@ -204,7 +206,7 @@ cmd_recipient (assuan_context_t ctx, char *line)
     remusr = rcpts;
   */
 
-  err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden,
+  err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden, file,
                             &ctrl->server_local->recplist);
 
   if (err)
index a4974be..6a7a87e 100644 (file)
@@ -156,6 +156,7 @@ mk_notation_policy_etc (PKT_signature *sig,
           if (DBG_LOOKUP)
             log_debug ("setting Signer's UID to '%s'\n", mbox);
           build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox));
+          xfree (mbox);
         }
     }
 }
@@ -604,7 +605,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
          * data, it is not possible to know the used length
          * without a double read of the file - to avoid that
          * we simple use partial length packets. */
-        if ( ptmode == 't' )
+        if ( ptmode == 't' || ptmode == 'u' || ptmode == 'm')
          filesize = 0;
       }
     else
@@ -627,6 +628,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
             log_error ("build_packet(PLAINTEXT) failed: %s\n",
                        gpg_strerror (rc) );
         pt->buf = NULL;
+        free_packet (&pkt);
     }
     else {
         byte copy_buffer[4096];
@@ -690,7 +692,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
 
       if (sig->version >= 4)
         {
-          build_sig_subpkt_from_sig (sig);
+          build_sig_subpkt_from_sig (sig, pk);
           mk_notation_policy_etc (sig, NULL, pk);
         }
 
@@ -1031,7 +1033,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
     }
     else {
         rc = write_plaintext_packet (out, inp, fname,
-                                     opt.textmode && !outfile ? 't':'b');
+                                     opt.textmode && !outfile ?
+                                     (opt.mimemode? 'm':'t'):'b');
     }
 
     /* catch errors from above */
@@ -1335,7 +1338,8 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
 
     /* Pipe data through all filters; i.e. write the signed stuff */
     /*(current filters: zip - encrypt - armor)*/
-    rc = write_plaintext_packet (out, inp, fname, opt.textmode ? 't':'b');
+    rc = write_plaintext_packet (out, inp, fname,
+                                 opt.textmode ? (opt.mimemode?'m':'t'):'b');
     if (rc)
        goto leave;
 
@@ -1456,7 +1460,7 @@ make_keysig_packet (PKT_signature **ret_sig, PKT_public_key *pk,
       sig->expiredate=sig->timestamp+duration;
     sig->sig_class = sigclass;
 
-    build_sig_subpkt_from_sig( sig );
+    build_sig_subpkt_from_sig (sig, pksk);
     mk_notation_policy_etc (sig, pk, pksk);
 
     /* Crucial that the call to mksubpkt comes LAST before the calls
@@ -1559,7 +1563,7 @@ update_keysig_packet( PKT_signature **ret_sig,
        automagically lower any sig expiration dates to correctly
        correspond to the differences in the timestamps (i.e. the
        duration will shrink).  */
-    build_sig_subpkt_from_sig( sig );
+    build_sig_subpkt_from_sig (sig, pksk);
 
     if (mksubpkt)
       rc = (*mksubpkt)(sig, opaque);
index c12bab1..cab1448 100644 (file)
@@ -59,4 +59,6 @@ do_test (int argc, char *argv[])
 
   rc = keydb_get_keyblock (hd1, &kb1);
   TEST_P ("", ! rc);
+
+  keydb_release (hd1);
 }
index f0b7778..3606e2e 100644 (file)
@@ -27,7 +27,7 @@ do_test (int argc, char *argv[])
   int rc;
   KEYDB_HANDLE hd1, hd2;
   KEYDB_SEARCH_DESC desc1, desc2;
-  KBNODE kb1, kb2;
+  KBNODE kb1, kb2, p;
   char *uid1;
   char *uid2;
   char *fname;
@@ -75,17 +75,19 @@ do_test (int argc, char *argv[])
   if (rc)
     ABORT ("Failed to get keyblock for DBFC6AD9");
 
-  while (kb1 && kb1->pkt->pkttype != PKT_USER_ID)
-    kb1 = kb1->next;
-  if (! kb1)
+  p = kb1;
+  while (p && p->pkt->pkttype != PKT_USER_ID)
+    p = p->next;
+  if (! p)
     ABORT ("DBFC6AD9 has no user id packet");
-  uid1 = kb1->pkt->pkt.user_id->name;
+  uid1 = p->pkt->pkt.user_id->name;
 
-  while (kb2 && kb2->pkt->pkttype != PKT_USER_ID)
-    kb2 = kb2->next;
-  if (! kb2)
+  p = kb2;
+  while (p && p->pkt->pkttype != PKT_USER_ID)
+    p = p->next;
+  if (! p)
     ABORT ("1E42B367 has no user id packet");
-  uid2 = kb2->pkt->pkt.user_id->name;
+  uid2 = p->pkt->pkt.user_id->name;
 
   if (verbose)
     {
@@ -94,4 +96,9 @@ do_test (int argc, char *argv[])
     }
 
   TEST_P ("cache consistency", strcmp (uid1, uid2) != 0);
+
+  release_kbnode (kb1);
+  release_kbnode (kb2);
+  keydb_release (hd1);
+  keydb_release (hd2);
 }
index 9576027..f3fc653 100644 (file)
@@ -606,5 +606,6 @@ main (int argc, char *argv[])
       log_fatal ("Message is too short, nothing to test.\n");
   }
 
+  xfree (filename);
   return failed;
 }
index a414709..e27788e 100644 (file)
@@ -119,6 +119,7 @@ static int in_transaction;
 
 \f
 static void open_db (void);
+static void create_hashtable (TRUSTREC *vr, int type);
 
 
 \f
@@ -582,8 +583,13 @@ create_version_record (void)
   rec.rectype = RECTYPE_VER;
   rec.recnum = 0;
   rc = tdbio_write_record (&rec);
+
   if (!rc)
     tdbio_sync ();
+
+  if (!rc)
+    create_hashtable (&rec, 0);
+
   return rc;
 }
 
@@ -957,8 +963,6 @@ get_trusthashrec(void)
       if (rc)
         log_fatal (_("%s: error reading version record: %s\n"),
                    db_name, gpg_strerror (rc) );
-      if (!vr.r.ver.trusthashtbl)
-        create_hashtable (&vr, 0);
 
       trusthashtbl = vr.r.ver.trusthashtbl;
     }
index 42c91f8..6f50759 100644 (file)
@@ -177,6 +177,17 @@ keyserver_import_keyid (u32 *keyid, void *dummy)
 }
 
 int
+keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
+                        struct keyserver_spec *keyserver)
+{
+  (void)ctrl;
+  (void)fprint;
+  (void)fprint_len;
+  (void)keyserver;
+  return -1;
+}
+
+int
 keyserver_import_cert (const char *name)
 {
   (void)name;
@@ -217,6 +228,15 @@ keyserver_import_ldap (const char *name)
   return -1;
 }
 
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+  (void)ctrl;
+  (void)fname;
+  (void)r_keyblock;
+  return -1;
+}
+
 /* Stub:
  * No encryption here but mainproc links to these functions.
  */
index 5929c5f..6ca4f88 100644 (file)
@@ -240,5 +240,6 @@ copy_clearsig_text( IOBUF out, IOBUF inp, gcry_md_hd_t md,
     if( truncated )
        log_info(_("input line longer than %d characters\n"), MAX_LINELEN );
 
+    xfree (buffer);
     return 0; /* okay */
 }
index 527a23d..dd74d18 100644 (file)
@@ -1022,17 +1022,18 @@ tdb_get_validity_core (ctrl_t ctrl,
 #ifdef USE_TOFU
   if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
     {
-      kbnode_t user_id_node = NULL; /* Silence -Wmaybe-uninitialized.  */
+      kbnode_t user_id_node = NULL;
+      kbnode_t n = NULL;       /* Silence -Wmaybe-uninitialized.  */
       int user_ids = 0;
       int user_ids_expired = 0;
 
       /* If the caller didn't supply a user id then iterate over all
         uids.  */
       if (! uid)
-       user_id_node = get_pubkeyblock (main_pk->keyid);
+       user_id_node = n = get_pubkeyblock (main_pk->keyid);
 
       while (uid
-            || (user_id_node = find_next_kbnode (user_id_node, PKT_USER_ID)))
+            || (n = find_next_kbnode (n, PKT_USER_ID)))
        {
          unsigned int tl;
          PKT_user_id *user_id;
@@ -1040,7 +1041,7 @@ tdb_get_validity_core (ctrl_t ctrl,
          if (uid)
            user_id = uid;
          else
-           user_id = user_id_node->pkt->pkt.user_id;
+           user_id = n->pkt->pkt.user_id;
 
           /* If the user id is revoked or expired, then skip it.  */
          if (user_id->is_revoked || user_id->is_expired)
@@ -1094,6 +1095,7 @@ tdb_get_validity_core (ctrl_t ctrl,
               now.  */
            break;
        }
+      release_kbnode (user_id_node);
     }
 #endif /*USE_TOFU*/
 
index fc6644c..ddcb467 100644 (file)
@@ -114,7 +114,7 @@ create_tupledesc (tupledesc_t *r_desc, void *data, size_t datalen)
   (*r_desc)->data = data;
   (*r_desc)->datalen = datalen;
   (*r_desc)->pos = 0;
-  (*r_desc)->refcount++;
+  (*r_desc)->refcount = 1;
   return 0;
 }
 
index 556605a..896f137 100644 (file)
@@ -661,18 +661,24 @@ create_blob_finish (KEYBOXBLOB blob)
 
   /* do the fixups */
   if (blob->fixup_out_of_core)
-    return gpg_error (GPG_ERR_ENOMEM);
+    {
+      xfree (p);
+      return gpg_error (GPG_ERR_ENOMEM);
+    }
 
   {
-    struct fixup_list *fl;
-    for (fl = blob->fixups; fl; fl = fl->next)
+    struct fixup_list *fl, *next;
+    for (fl = blob->fixups; fl; fl = next)
       {
         assert (fl->off+4 <= n);
         p[fl->off+0] = fl->val >> 24;
         p[fl->off+1] = fl->val >> 16;
         p[fl->off+2] = fl->val >>  8;
         p[fl->off+3] = fl->val;
+        next = fl->next;
+        xfree (fl);
       }
+    blob->fixups = NULL;
   }
 
   /* Compute and store the SHA-1 checksum. */
@@ -680,8 +686,12 @@ create_blob_finish (KEYBOXBLOB blob)
 
   pp = xtrymalloc (n);
   if ( !pp )
-    return gpg_error_from_syserror ();
+    {
+      xfree (p);
+      return gpg_error_from_syserror ();
+    }
   memcpy (pp , p, n);
+  xfree (p);
   blob->blob = pp;
   blob->bloblen = n;
 
@@ -1000,7 +1010,11 @@ _keybox_release_blob (KEYBOXBLOB blob)
   int i;
   if (!blob)
     return;
-  /* hmmm: release membuf here?*/
+  if (blob->buf)
+    {
+      size_t len;
+      xfree (get_membuf (blob->buf, &len));
+    }
   xfree (blob->keys );
   xfree (blob->serialbuf);
   for (i=0; i < blob->nuids; i++)
index f1b8df9..3232413 100644 (file)
@@ -1,6 +1,6 @@
 EXTRA_DIST = intl.m4 intldir.m4 glibc2.m4 lock.m4 visibility.m4 intmax.m4 longdouble.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4  codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 stdint_h.m4 uintmax_t.m4
 
-EXTRA_DIST += ldap.m4 libcurl.m4 libusb.m4 tar-ustar.m4 readline.m4
+EXTRA_DIST += ldap.m4 libcurl.m4 libusb.m4 tar-ustar.m4 readline.m4 pkg.m4
 
 EXTRA_DIST += gnupg-pth.m4
 
diff --git a/m4/pkg.m4 b/m4/pkg.m4
new file mode 100644 (file)
index 0000000..78953b7
--- /dev/null
+++ b/m4/pkg.m4
@@ -0,0 +1,214 @@
+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=m4_default([$1], [0.9.0])
+       AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
+               PKG_CONFIG=""
+       fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists.  Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_default([$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes ],
+                    [pkg_failed=yes])
+ else
+    pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+        AC_MSG_RESULT([no])
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+        else
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+       m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+        ])
+elif test $pkg_failed = untried; then
+        AC_MSG_RESULT([no])
+       m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+        ])
+else
+       $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+       $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+       $3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+
+# PKG_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable pkgconfigdir as the location where a module
+# should install pkg-config .pc files. By default the directory is
+# $libdir/pkgconfig, but the default can be changed by passing
+# DIRECTORY. The user can override through the --with-pkgconfigdir
+# parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_INSTALLDIR
+
+
+# PKG_NOARCH_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable noarch_pkgconfigdir as the location where a
+# module should install arch-independent pkg-config .pc files. By
+# default the directory is $datadir/pkgconfig, but the default can be
+# changed by passing DIRECTORY. The user can override through the
+# --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_NOARCH_INSTALLDIR
+
+
+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])# PKG_CHECK_VAR
index 66b33de..086ac26 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -1859,13 +1859,10 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: es descarta: %s\n"
 
-#, fuzzy
-msgid "exporting secret keys not allowed\n"
-msgstr "s'està escrivint la clau secreta a «%s»\n"
-
 #, fuzzy, c-format
-msgid "key %s: PGP 2.x style key - skipped\n"
-msgstr "clau %08lX: clau d'estil PGP 2.x - es descarta\n"
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "s'està escrivint en «%s»\n"
 
 #, fuzzy, c-format
 msgid "key %s: key material on-card - skipped\n"
@@ -1873,6 +1870,14 @@ msgstr ""
 "clau %08lX: la signatura de la subclau és en el lloc equivocat - es "
 "descarta\n"
 
+#, fuzzy
+msgid "exporting secret keys not allowed\n"
+msgstr "s'està escrivint la clau secreta a «%s»\n"
+
+#, fuzzy, c-format
+msgid "key %s: PGP 2.x style key - skipped\n"
+msgstr "clau %08lX: clau d'estil PGP 2.x - es descarta\n"
+
 msgid "WARNING: nothing exported\n"
 msgstr "AVÍS: no s'ha exportat res\n"
 
@@ -1995,6 +2000,11 @@ msgstr "genera un nou parell de claus"
 msgid "quickly add a new user-id"
 msgstr "genera un nou parell de claus"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "genera un nou parell de claus"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2343,6 +2353,10 @@ msgstr "%s:%d: opcions d'importanció no vàlides\n"
 msgid "invalid import options\n"
 msgstr "opcions d'importació no vàlides\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "opcions d'importació no vàlides\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d opcions d'exportació no vàlides\n"
@@ -2685,6 +2699,10 @@ msgstr "actualitza la base de dades de confiança"
 msgid "do not update the trustdb after import"
 msgstr "actualitza la base de dades de confiança"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "mostra empremta"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2695,6 +2713,9 @@ msgstr "la clau secreta és inusable"
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "es descarta un bloc de tipus %d\n"
@@ -2835,11 +2856,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "no s'ha trobat cap anell escrivible: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "s'està escrivint en «%s»\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "error mentre s'escrivia l'anell «%s»: %s\n"
@@ -3653,6 +3669,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "La clau no ha canviat, per tant no cal actualització.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "La generació de claus ha fallat: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "error: l'empremta digital és invàlida\n"
 
@@ -3992,6 +4013,10 @@ msgid "no secret key\n"
 msgstr "ho hi ha clau secreta\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "l'ID d'usuari «%s» ja està revocat\n"
 
@@ -4526,10 +4551,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Anell"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "es descarta «%s»: %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Empremtes digital de la clau primària:"
 
@@ -4653,6 +4674,10 @@ msgid "no keyserver known\n"
 msgstr "error de servidor de claus"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "es descarta «%s»: %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr "s'està sol·licitant la clau %08lX de %s\n"
 
index 855b825..96bb049 100644 (file)
--- a/po/cs.po
+++ b/po/cs.po
@@ -1709,6 +1709,15 @@ msgstr "odstranit při exportu z klíče vše, co lze"
 msgid " - skipped"
 msgstr " – přeskočeno"
 
+# g10/import.c:766 g10/openfile.c:261#, c-format
+#, c-format
+msgid "writing to '%s'\n"
+msgstr "zapisuje se do „%s“\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "klíč %s: tělo klíče je na kartě – přeskočeno\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "exportování tajného klíče není povoleno\n"
 
@@ -1716,10 +1725,6 @@ msgstr "exportování tajného klíče není povoleno\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "klíč %s: PGP 2.x klíč – přeskočeno\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "klíč %s: tělo klíče je na kartě – přeskočeno\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "VAROVÁNÍ: nebylo nic vyexportováno\n"
 
@@ -1836,6 +1841,11 @@ msgstr "rychle vytvořit nový pár klíčů"
 msgid "quickly add a new user-id"
 msgstr "rychle přidat novou identitu uživatele"
 
+#, fuzzy
+#| msgid "quickly add a new user-id"
+msgid "quickly revoke a user-id"
+msgstr "rychle přidat novou identitu uživatele"
+
 msgid "full featured key pair generation"
 msgstr "komplexní vytvoření páru klíčů"
 
@@ -2164,6 +2174,11 @@ msgstr "%s:%d: neplatný parametr pro import\n"
 msgid "invalid import options\n"
 msgstr "neplatný parametr pro import\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "neplatný parametr pro výpis\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: neplatný parametr pro export\n"
@@ -2485,6 +2500,11 @@ msgstr "nemazat údaje o důvěře během importu"
 msgid "do not update the trustdb after import"
 msgstr "neaktualizovat databázi důvěry po importu"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "vypsat otisk klíče"
+
 msgid "only accept updates to existing keys"
 msgstr "přijímat aktualizace pouze u existujících klíčů"
 
@@ -2494,6 +2514,9 @@ msgstr "odstranit z klíče po importu nepoužitelné části"
 msgid "remove as much as possible from key after import"
 msgstr "odstranit po importu z klíče vše, co lze"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "blok typu %d byl přeskočen\n"
@@ -2636,11 +2659,6 @@ msgstr "klíč %s: nový klíč - přeskočen\n"
 msgid "no writable keyring found: %s\n"
 msgstr "nenalezen zapisovatelný soubor klíčů (keyring): %s\n"
 
-# g10/import.c:766 g10/openfile.c:261#, c-format
-#, c-format
-msgid "writing to '%s'\n"
-msgstr "zapisuje se do „%s“\n"
-
 #, c-format
 msgid "error writing keyring '%s': %s\n"
 msgstr "chyba při zápisu souboru klíčů (keyring) „%s“: %s\n"
@@ -3376,6 +3394,11 @@ msgstr "aktualizace selhala: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "Klíč nebyl změněn, takže není potřeba jej aktualizovat.\n"
 
+#, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Vytvoření klíče se nepodařilo: %s\n"
+
 #, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "„%s“ není otisk\n"
@@ -3684,6 +3707,10 @@ msgid "no secret key\n"
 msgstr "neexistuje tajný klíč\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "uživatelské ID „%s“ je již revokováno\n"
 
@@ -4194,10 +4221,6 @@ msgstr[2] "Pozor: %lu klíč(ů) přeskočen(o) kvůli jejich přílišné velik
 msgid "Keyring"
 msgstr "Soubor klíčů (keyring)"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "přeskočen „%s“: %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Otisk primárního klíče:"
 
@@ -4321,6 +4344,10 @@ msgid "no keyserver known\n"
 msgstr "žádná operace se serverem klíčů!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "přeskočen „%s“: %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "posílám klíč %s na %s\n"
 
index e7d4b68..2f8fb37 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -1819,6 +1819,15 @@ msgstr "fjern så meget som muligt fra nøglen under eksport"
 msgid " - skipped"
 msgstr "%s: udelod: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "skriver til »%s«\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "nøgle %s: nøglemateriale på kort - udeladt\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "eksport af hemmelige nøgler er ikke tilladt\n"
 
@@ -1826,10 +1835,6 @@ msgstr "eksport af hemmelige nøgler er ikke tilladt\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "nøgle %s: nøgle i PGP 2.x-stil - udeladt\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "nøgle %s: nøglemateriale på kort - udeladt\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "ADVARSEL: intet blev eksporteret\n"
 
@@ -1948,6 +1953,11 @@ msgstr "opret et nyt nøglepar"
 msgid "quickly add a new user-id"
 msgstr "opret et nyt nøglepar"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "opret et nyt nøglepar"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2300,6 +2310,11 @@ msgstr "%s:%d: ugyldige importindstillinger\n"
 msgid "invalid import options\n"
 msgstr "ugyldige importindstillinger\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "ugyldige listeindstillinger\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: ugyldige eksportindstillinger\n"
@@ -2628,6 +2643,11 @@ msgstr "opdater ikke trustdb efter import"
 msgid "do not update the trustdb after import"
 msgstr "opdater ikke trustdb efter import"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "vis nøglefingeraftryk"
+
 msgid "only accept updates to existing keys"
 msgstr "accepter kun opdateringer til eksisterende nøgler"
 
@@ -2637,6 +2657,9 @@ msgstr "fjern ubrugelige dele fra nøgle efter import"
 msgid "remove as much as possible from key after import"
 msgstr "fjern så meget som muligt fra nøgle efter import"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "     udelader bloktype %d\n"
@@ -2782,11 +2805,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "ingen skrivbar nøglering fundet: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "skriver til »%s«\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "fejl ved skrivning af nøglering »%s«: %s\n"
@@ -3561,6 +3579,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Nøgle ikke ændret så ingen opdatering krævet.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Nøgleoprettelse mislykkedes: %s\n"
+
+#, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "ugyldig fingeraftryk"
@@ -3886,6 +3909,10 @@ msgid "no secret key\n"
 msgstr "ingen hemmelig nøgle\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "bruger-id »%s« er allerede tilbagekaldt\n"
 
@@ -4416,10 +4443,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Nøglering"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "udelod »%s«: %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Primær nøglefingeraftryk:"
 
@@ -4539,6 +4562,10 @@ msgid "no keyserver known\n"
 msgstr "ingen nøgleserverhandling!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "udelod »%s«: %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "sender nøgle %s til %s\n"
 
index 8bbd5d3..f341c5f 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gnupg-2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2016-06-16 17:04+0200\n"
+"PO-Revision-Date: 2016-07-14 15:55+0200\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
@@ -1707,6 +1707,14 @@ msgstr "Während des Exports soviel wie möglich vom Schlüssel entfernen"
 msgid " - skipped"
 msgstr " - übersprungen"
 
+#, c-format
+msgid "writing to '%s'\n"
+msgstr "Schreiben nach '%s'\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "Schlüssel %s: Schlüsselmaterial ist auf einer Karte - übersprungen\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "Exportieren geheimer Schlüssel ist nicht erlaubt\n"
 
@@ -1714,10 +1722,6 @@ msgstr "Exportieren geheimer Schlüssel ist nicht erlaubt\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "Schlüssel %s: PGP 2.x-artiger Schlüssel - übersprungen\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "Schlüssel %s: Schlüsselmaterial ist auf einer Karte - übersprungen\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "WARNUNG: Nichts exportiert\n"
 
@@ -1828,6 +1832,9 @@ msgstr "Schnell ein neues Schlüsselpaar erzeugen"
 msgid "quickly add a new user-id"
 msgstr "Schnell eine neue User-ID anfügen"
 
+msgid "quickly revoke a user-id"
+msgstr "Schnell eine User-ID widerrufen"
+
 msgid "full featured key pair generation"
 msgstr "Ein neues Schlüsselpaar erzeugen (alle Optionen)"
 
@@ -2152,6 +2159,10 @@ msgid "invalid import options\n"
 msgstr "Ungültige Import-Option\n"
 
 #, c-format
+msgid "invalid filter option: %s\n"
+msgstr "Ungültige Filter-Option: %s\n"
+
+#, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: ungültige Export-Option.\n"
 
@@ -2478,6 +2489,9 @@ msgstr "die \"Ownertrust\" Werte beim Import nicht löschen"
 msgid "do not update the trustdb after import"
 msgstr "ändern Sie die \"Trust\"-Datenbank nach dem Import nicht"
 
+msgid "show key during import"
+msgstr "Schlüssel beim Import anzeigen"
+
 msgid "only accept updates to existing keys"
 msgstr "Nur Änderungen bereits existierender Schlüssel vornehmen"
 
@@ -2487,6 +2501,9 @@ msgstr "entferne nach dem Import unbrauchbare Teile des Schlüssels"
 msgid "remove as much as possible from key after import"
 msgstr "nach dem Import soviel wie möglich aus dem Schlüssel entfernen"
 
+msgid "run import filters and export key immediately"
+msgstr "Import-Filter anwenden und Schlüssel direkt exportieren"
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "überspringe den Block vom Typ %d\n"
@@ -2632,10 +2649,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "kein schreibbarer Schlüsselbund gefunden: %s\n"
 
 #, c-format
-msgid "writing to '%s'\n"
-msgstr "Schreiben nach '%s'\n"
-
-#, c-format
 msgid "error writing keyring '%s': %s\n"
 msgstr "Fehler beim Schreiben des Schlüsselbundes `%s': %s\n"
 
@@ -3387,6 +3400,10 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Schlüssel ist nicht geändert worden, also ist kein Speichern nötig.\n"
 
 #, c-format
+msgid "User ID revocation failed: %s\n"
+msgstr "Widerufen der User-ID fehlgeschlagen: %s\n"
+
+#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\" ist kein Fingerabdruck\n"
 
@@ -3701,6 +3718,10 @@ msgid "no secret key\n"
 msgstr "Kein geheimer Schlüssel\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr "Versuch eine nicht-User-ID zu widerrufen: %s\n"
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "User-ID \"%s\" ist bereits widerrufen\n"
 
@@ -4202,10 +4223,6 @@ msgstr[1] "WARNUNG: %lu Schlüssel übersprungen, da sie zu groß sind\n"
 msgid "Keyring"
 msgstr "Schlüsselbund"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "übersprungen \"%s\": %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Haupt-Fingerabdruck  ="
 
@@ -4320,6 +4337,10 @@ msgid "no keyserver known\n"
 msgstr "Kein Schlüsselserver bekannt\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "übersprungen \"%s\": %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "sende Schlüssel %s auf %s\n"
 
index 7e3fcf2..0160ccb 100644 (file)
--- a/po/el.po
+++ b/po/el.po
@@ -1792,6 +1792,16 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: ðáñáëåßöèçêå: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "åããñáöÞ óôï  `%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr ""
+"êëåéäß %08lX: ç õðïãñáöÞ ôïõ õðïêëåéäéïý óå ëÜèïò óçìåßï - ðáñáëåßöèçêå\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "åããñáöÞ ôïõ ìõóôéêïý êëåéäéïý óôï `%s'\n"
@@ -1800,11 +1810,6 @@ msgstr "
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "êëåéäß %08lX:  êëåéäß ôýðïõ PGP 2.x - ðáñáëåßöèçêå\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr ""
-"êëåéäß %08lX: ç õðïãñáöÞ ôïõ õðïêëåéäéïý óå ëÜèïò óçìåßï - ðáñáëåßöèçêå\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "ÐÑÏÅÉÄÏÐÏÉÇÓÇ: äåí Ýãéíå êáììßá åîáãùãÞ\n"
 
@@ -1925,6 +1930,11 @@ msgstr "
 msgid "quickly add a new user-id"
 msgstr "äçìéïõñãßá åíüò íÝïõ æåýãïõò êëåéäéþí"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "äçìéïõñãßá åíüò íÝïõ æåýãïõò êëåéäéþí"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2264,6 +2274,10 @@ msgstr "%s:%d: 
 msgid "invalid import options\n"
 msgstr "ìç Ýãêõñåò åðéëïãÝò åéãáãùãÞò\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "ìç Ýãêõñåò åðéëïãÝò åéãáãùãÞò\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: ìç Ýãêõñåò åðéëïãÝò åîáãùãÞò\n"
@@ -2606,6 +2620,10 @@ msgstr "
 msgid "do not update the trustdb after import"
 msgstr "áíáíÝùóç ôçò âÜóçò äåäïìÝíùí åìðéóôïóýíçò"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "áðåéêüíéóç ôïõ fingerprint"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2616,6 +2634,9 @@ msgstr "
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "ðáñÜëåéøç ôìÞìáôïò ôïõ ôýðïõ %d\n"
@@ -2756,11 +2777,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "äåí âñåèçêå åããñÜøéìç êëåéäïèÞêç: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "åããñáöÞ óôï  `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "áäõíáìßá åããñáöÞò ôçò êëåéäïèÞêçò `%s': %s\n"
@@ -3559,6 +3575,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Ôï êëåéäß äåí Üëëáîå ïðüôå äåí ÷ñåéÜæåôáé åíçìÝñùóç.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Ç äçìéïõñãßá êëåéäéïý áðÝôõ÷å: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "óöÜëìá: ìç Ýãêõñï áðïôýðùìá\n"
 
@@ -3894,6 +3915,10 @@ msgid "no secret key\n"
 msgstr "êáíÝíá ìõóôéêü êëåéäß\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "ôï user ID \"%s\" Ý÷åé Þäç áíáêëçèåß\n"
 
@@ -4423,10 +4448,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "ÊëåéäïèÞêç"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "ðáñáëåßöèçêå `%s': %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Áðïôýðùìá ðñùôåýùí êëåéäéïý:"
 
@@ -4546,6 +4567,10 @@ msgid "no keyserver known\n"
 msgstr "ìç Ýãêõñåò åðéëïãÝò åîáãùãÞò\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "ðáñáëåßöèçêå `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index f8e64f5..958c534 100644 (file)
--- a/po/eo.po
+++ b/po/eo.po
@@ -1780,6 +1780,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: ignorita: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "skribas al '%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "þlosilo %08lX: revokatestilo en maløusta loko - ignorita\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "skribas sekretan þlosilon al '%s'\n"
@@ -1788,10 +1797,6 @@ msgstr "skribas sekretan 
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "þlosilo %08lX: PGP-2.x-stila þlosilo - ignorita\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "þlosilo %08lX: revokatestilo en maløusta loko - ignorita\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "AVERTO: nenio estis eksportita\n"
 
@@ -1911,6 +1916,11 @@ msgstr "krei novan 
 msgid "quickly add a new user-id"
 msgstr "krei novan þlosilparon"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "krei novan þlosilparon"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2249,6 +2259,10 @@ msgid "invalid import options\n"
 msgstr "nevalida kiraso"
 
 #, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "nevalida kiraso"
+
+#, fuzzy, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "AVERTO: '%s' estas malplena dosiero\n"
 
@@ -2590,6 +2604,10 @@ msgstr "aktualigi la fido-datenaron"
 msgid "do not update the trustdb after import"
 msgstr "aktualigi la fido-datenaron"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "montri fingrospuron"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2600,6 +2618,9 @@ msgstr "neuzebla sekreta 
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "ignoras blokon de speco %d\n"
@@ -2740,11 +2761,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "neniu skribebla þlosilaro trovita: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "skribas al '%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "eraro dum skribado de þlosilaro '%s': %s\n"
@@ -3546,6 +3562,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Þlosilo ne þanøita, do aktualigo ne necesas.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Kreado de þlosiloj malsukcesis: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "%s: nevalida dosiero-versio %d\n"
 
@@ -3869,6 +3890,10 @@ msgstr "
 msgid "no secret key\n"
 msgstr "mankas sekreta þlosilo\n"
 
+#, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "Uzantidentigilo \"%s\" estas revokita.\n"
@@ -4396,10 +4421,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Þlosilaro"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "ignoris '%s': %s\n"
-
 #, fuzzy
 msgid "Primary key fingerprint:"
 msgstr "listigi þlosilojn kaj fingroþpurojn"
@@ -4524,6 +4545,10 @@ msgid "no keyserver known\n"
 msgstr "nevalida þlosilaro"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "ignoris '%s': %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 385ea2b..5e374f5 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -1838,6 +1838,15 @@ msgstr "borrar tanto como sea posible de la clave al exportar"
 msgid " - skipped"
 msgstr "%s: omitido: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "escribiendo en `%s'\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "clave %s: material de la clave en la tarjeta - omitida\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "no se permite exportar claves secretas\n"
 
@@ -1845,10 +1854,6 @@ msgstr "no se permite exportar claves secretas\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "clave %s: clave estilo PGP 2.x - omitida\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "clave %s: material de la clave en la tarjeta - omitida\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "ATENCIÓN: no se ha exportado nada\n"
 
@@ -1967,6 +1972,11 @@ msgstr "genera un nuevo par de claves"
 msgid "quickly add a new user-id"
 msgstr "genera un nuevo par de claves"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "genera un nuevo par de claves"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2326,6 +2336,11 @@ msgstr "%s:%d: opciones de importaci
 msgid "invalid import options\n"
 msgstr "opciones de importación inválidas\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "lista de opciones inválida\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: opciones de exportación inválidas\n"
@@ -2657,6 +2672,11 @@ msgstr "no actualiza la base de datos de confianza despu
 msgid "do not update the trustdb after import"
 msgstr "no actualiza la base de datos de confianza después de importar"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "muestra huella dactilar de la clave"
+
 msgid "only accept updates to existing keys"
 msgstr "sólo aceptar actualizaciones de claves ya existentes"
 
@@ -2666,6 +2686,9 @@ msgstr "borrar partes in
 msgid "remove as much as possible from key after import"
 msgstr "borrar tanto como sea posible de la clave tras importar"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "omitiendo bloque de tipo %d\n"
@@ -2812,11 +2835,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "anillo de claves no escribible encontrado: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "escribiendo en `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "error escribiendo anillo `%s': %s\n"
@@ -3573,6 +3591,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Clave sin cambios, no se necesita actualización.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Creación de la clave fallida: %s\n"
+
+#, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "huella dactilar no válida"
@@ -3890,6 +3913,11 @@ msgstr "
 msgid "no secret key\n"
 msgstr "no hay clave secreta\n"
 
+#, fuzzy, c-format
+#| msgid "revoke a user ID"
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr "revocar un identificador de usuario"
+
 #, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "ID de usuario \"%s\" ya ha sido revocado\n"
@@ -4415,10 +4443,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Anillo de claves"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "omitido \"%s\": %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Huellas dactilares de la clave primaria:"
 
@@ -4539,6 +4563,10 @@ msgid "no keyserver known\n"
 msgstr "¡no se solicita ninguna acción al servidor de claves!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "omitido \"%s\": %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "enviando clave %s a %s\n"
 
@@ -10624,9 +10652,6 @@ msgstr ""
 #~ msgid "revuid"
 #~ msgstr "revidu"
 
-#~ msgid "revoke a user ID"
-#~ msgstr "revocar un identificador de usuario"
-
 #~ msgid "revkey"
 #~ msgstr "revcla"
 
index 4ca6566..5d9dcf3 100644 (file)
--- a/po/et.po
+++ b/po/et.po
@@ -1785,6 +1785,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: jätsin vahele: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "kirjutan faili `%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "võti %08lX: alamvõtme allkiri on vales kohas - jätan vahele\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "kirjutan salajase võtme faili `%s'\n"
@@ -1793,10 +1802,6 @@ msgstr "kirjutan salajase v
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "võti %08lX: PGP 2.x stiilis võti - jätsin vahele\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "võti %08lX: alamvõtme allkiri on vales kohas - jätan vahele\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "HOIATUS: midagi ei eksporditud\n"
 
@@ -1918,6 +1923,11 @@ msgstr "genereeri uus v
 msgid "quickly add a new user-id"
 msgstr "genereeri uus võtmepaar"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "genereeri uus võtmepaar"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2254,6 +2264,10 @@ msgstr "%s:%d: vigased impordi v
 msgid "invalid import options\n"
 msgstr "vigased impordi võtmed\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "vigased impordi võtmed\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: vigased ekspordi võtmed\n"
@@ -2591,6 +2605,10 @@ msgstr "uuenda usalduse andmebaasi"
 msgid "do not update the trustdb after import"
 msgstr "uuenda usalduse andmebaasi"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "näita sõrmejälge"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2601,6 +2619,9 @@ msgstr "mittekasutatav salajane v
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "jätan bloki tüübiga %d vahele\n"
@@ -2742,11 +2763,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "ei leia kirjutatavat võtmehoidlat: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "kirjutan faili `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "viga võtmehoidlasse `%s' kirjutamisel: %s\n"
@@ -3532,6 +3548,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Võtit ei muudetud, seega pole uuendamist vaja.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Võtme genereerimine ebaõnnestus: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "viga: vigane sõrmejälg\n"
 
@@ -3856,6 +3877,10 @@ msgid "no secret key\n"
 msgstr "salajast võtit pole\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "kasutaja ID \"%s\" on juba tühistatud\n"
 
@@ -4376,10 +4401,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Võtmehoidla"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "`%s' jätsin vahele: %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Primaarse võtme sõrmejälg:"
 
@@ -4499,6 +4520,10 @@ msgid "no keyserver known\n"
 msgstr "vigased ekspordi võtmed\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "`%s' jätsin vahele: %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 1b93bce..414f99b 100644 (file)
--- a/po/fi.po
+++ b/po/fi.po
@@ -1800,6 +1800,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: ohitettu: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "kirjoitetaan kohteeseen \"%s\"\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "avain %08lX: aliavaimen allekirjoitus väärässä paikassa - ohitetaan\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "kirjoitan salaisen avaimen kohteeseen \"%s\"\n"
@@ -1808,10 +1817,6 @@ msgstr "kirjoitan salaisen avaimen kohteeseen \"%s\"\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "avain %08lX: PGP 2.x -muodon avain - ohitetaan\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "avain %08lX: aliavaimen allekirjoitus väärässä paikassa - ohitetaan\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "VAROITUS: mitään ei viety\n"
 
@@ -1933,6 +1938,11 @@ msgstr "luo uusi avainpari"
 msgid "quickly add a new user-id"
 msgstr "luo uusi avainpari"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "luo uusi avainpari"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2269,6 +2279,10 @@ msgstr "%s:%d: virheelliset tuontivalitsimet\n"
 msgid "invalid import options\n"
 msgstr "virheelliset tuontivalitsimet\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "virheelliset tuontivalitsimet\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: virheelliset vientivalitsimet\n"
@@ -2607,6 +2621,10 @@ msgstr "päivitä luottamustietokanta"
 msgid "do not update the trustdb after import"
 msgstr "päivitä luottamustietokanta"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "näytä sormenjälki"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2617,6 +2635,9 @@ msgstr "salaista avainta ei voi käyttää"
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "ohitetaan tyypin %d lohko\n"
@@ -2759,11 +2780,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "kirjoitettavissa olevaa avainrengasta ei löydy: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "kirjoitetaan kohteeseen \"%s\"\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "virhe kirjoitettaessa avainrenkaaseen \"%s\": %s\n"
@@ -3553,6 +3569,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Päivitystä ei tarvita, koska avain ei ole muuttunut.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Avaimen luonti epäonnistui: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "virhe: sormenjälki on väärä\n"
 
@@ -3878,6 +3899,10 @@ msgid "no secret key\n"
 msgstr "salainen avain ei ole saatavilla\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "käyttäjätunnus \"%s\" on jo mitätöity\n"
 
@@ -4407,10 +4432,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Avainrengas"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "ohitetaan \"%s\": %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Ensisijaisen avaimen sormenjälki:"
 
@@ -4530,6 +4551,10 @@ msgid "no keyserver known\n"
 msgstr "virheelliset vientivalitsimet\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "ohitetaan \"%s\": %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 94ac188..c4b6e4d 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -1737,6 +1737,14 @@ msgstr "supprimer autant que possible de la clef pendant l'exportation"
 msgid " - skipped"
 msgstr " — ignoré"
 
+#, c-format
+msgid "writing to '%s'\n"
+msgstr "écriture de « %s »\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "clef %s : matériel de clef sur la carte — ignorée\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "il est interdit d'exporter les clefs secrètes\n"
 
@@ -1744,10 +1752,6 @@ msgstr "il est interdit d'exporter les clefs secrètes\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "clef %s : clef de type PGP 2.x — ignorée\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "clef %s : matériel de clef sur la carte — ignorée\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "Attention : rien n'a été exporté\n"
 
@@ -1865,6 +1869,11 @@ msgstr "générer rapidement une nouvelle paire de clefs"
 msgid "quickly add a new user-id"
 msgstr "générer rapidement une nouvelle paire de clefs"
 
+#, fuzzy
+#| msgid "quickly generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "générer rapidement une nouvelle paire de clefs"
+
 msgid "full featured key pair generation"
 msgstr "générer une paire de clefs complètes"
 
@@ -2206,6 +2215,11 @@ msgstr "%s : %d : options d'importation incorrectes\n"
 msgid "invalid import options\n"
 msgstr "options d'importation incorrectes\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "options de liste incorrectes\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s : %d : options d'exportation incorrectes\n"
@@ -2530,6 +2544,11 @@ msgstr "ne pas mettre à jour la base de confiance après l'importation"
 msgid "do not update the trustdb after import"
 msgstr "ne pas mettre à jour la base de confiance après l'importation"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "afficher l'empreinte de la clef"
+
 msgid "only accept updates to existing keys"
 msgstr "n'accepter que les mises à jour des clefs existantes"
 
@@ -2539,6 +2558,9 @@ msgstr "nettoyer les parties inutilisables de la clef après l'importation"
 msgid "remove as much as possible from key after import"
 msgstr "supprimer autant que possible de la clef après l'importation"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "un bloc de type %d a été ignoré\n"
@@ -2683,10 +2705,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "aucun porte-clefs accessible en écriture n'a été trouvé : %s\n"
 
 #, c-format
-msgid "writing to '%s'\n"
-msgstr "écriture de « %s »\n"
-
-#, c-format
 msgid "error writing keyring '%s': %s\n"
 msgstr "erreur d'écriture du porte-clefs « %s » : %s\n"
 
@@ -3434,6 +3452,11 @@ msgstr "échec de la mise à jour : %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "La clef n'a pas été modifiée donc la mise à jour est inutile.\n"
 
+#, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Échec de génération de la clef : %s\n"
+
 #, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "« %s » n’est pas une empreinte\n"
@@ -3755,6 +3778,10 @@ msgid "no secret key\n"
 msgstr "pas de clef secrète\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "l'identité « %s »\" est déjà révoquée.\n"
 
@@ -4276,10 +4303,6 @@ msgstr[1] "Attention : %lu clefs ignorées en raison de leur grande taille\n"
 msgid "Keyring"
 msgstr "Porte-clefs"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "« %s » a été ignorée : %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Empreinte de clef principale :"
 
@@ -4403,6 +4426,10 @@ msgid "no keyserver known\n"
 msgstr "pas d'action pour le serveur de clefs.\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "« %s » a été ignorée : %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "envoi de la clef %s à %s\n"
 
index 915deaf..c8c5a26 100644 (file)
--- a/po/gl.po
+++ b/po/gl.po
@@ -1794,6 +1794,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: omitido: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "escribindo a `%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "chave %08lX: sinatura da sub-chave nun lugar incorrecto - omitida\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "gravando a chave secreta en `%s'\n"
@@ -1802,10 +1811,6 @@ msgstr "gravando a chave secreta en `%s'\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "chave %08lX: chave estilo PGP 2.x - omitida\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "chave %08lX: sinatura da sub-chave nun lugar incorrecto - omitida\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "AVISO: non se exportou nada\n"
 
@@ -1926,6 +1931,11 @@ msgstr "xerar un novo par de chaves"
 msgid "quickly add a new user-id"
 msgstr "xerar un novo par de chaves"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "xerar un novo par de chaves"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2262,6 +2272,10 @@ msgstr "%s:%d: opci
 msgid "invalid import options\n"
 msgstr "opcións de importación non válidas\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "opcións de importación non válidas\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: opcións de exportación non válidas\n"
@@ -2601,6 +2615,10 @@ msgstr "actualiza-la base de datos de confianza"
 msgid "do not update the trustdb after import"
 msgstr "actualiza-la base de datos de confianza"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "amosar fingerprint"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2611,6 +2629,9 @@ msgstr "chave secreta non utilizable"
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "pasando por alto un bloque de tipo %d\n"
@@ -2751,11 +2772,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "non se atopou un chaveiro no que se poida escribir: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "escribindo a `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "erro escribindo no chaveiro `%s': %s\n"
@@ -3558,6 +3574,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "A chave non cambiou, polo que non fai falla actualizar.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "A xeración da chave fallou: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "erro: pegada dactilar non válida\n"
 
@@ -3891,6 +3912,10 @@ msgid "no secret key\n"
 msgstr "non hai chave secreta\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "o ID de usuario \"%s\" xa está revocado\n"
 
@@ -4421,10 +4446,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Chaveiro"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "omítese `%s': %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Pegada dactilar da chave primaria:"
 
@@ -4546,6 +4567,10 @@ msgid "no keyserver known\n"
 msgstr "opcións de exportación non válidas\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "omítese `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index a37b430..8505a8f 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -1781,6 +1781,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: kihagyva: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "Írok a \"%s\" állományba.\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "%08lX kulcs: Alkulcsaláírás rossz helyen - kihagytam.\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "Írom a titkos kulcsot a %s állományba.\n"
@@ -1789,10 +1798,6 @@ msgstr "
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "%08lX kulcs: PGP 2.x stílusú kulcs - kihagytam.\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "%08lX kulcs: Alkulcsaláírás rossz helyen - kihagytam.\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "FIGYELEM: Semmit sem exportáltam.\n"
 
@@ -1914,6 +1919,11 @@ msgstr "
 msgid "quickly add a new user-id"
 msgstr "új kulcspár létrehozása"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "új kulcspár létrehozása"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2250,6 +2260,10 @@ msgstr "%s:%d: 
 msgid "invalid import options\n"
 msgstr "Érvénytelen import opciók!\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "Érvénytelen import opciók!\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: Érvénytelen export opciók!\n"
@@ -2589,6 +2603,10 @@ msgstr "bizalmi adatb
 msgid "do not update the trustdb after import"
 msgstr "bizalmi adatbázis frissítése"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "megmutatja az ujjlenyomatot"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2599,6 +2617,9 @@ msgstr "haszn
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "%d típusú blokkot kihagyom.\n"
@@ -2739,11 +2760,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "Nem írható kulcskarikát találtam: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "Írok a \"%s\" állományba.\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "Hiba a \"%s\" kulcskarika írásakor: %s\n"
@@ -3531,6 +3547,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "A kulcs nem változott, nincs szükség frissítésre.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Kulcsgenerálás sikertelen: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "Hiba: Érvénytelen ujjlenyomat.\n"
 
@@ -3857,6 +3878,10 @@ msgid "no secret key\n"
 msgstr "Nincs titkos kulcs.\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "\"%s\" felhasználói azonosítót már visszavonták.\n"
 
@@ -4386,10 +4411,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Kulcskarika"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "Kihagytam \"%s\"-t: %s.\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Elsõdlegeskulcs-ujjlenyomat:"
 
@@ -4510,6 +4531,10 @@ msgid "no keyserver known\n"
 msgstr "Érvénytelen export opciók!\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "Kihagytam \"%s\"-t: %s.\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 04a3e98..f1fbc44 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -1786,6 +1786,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: dilewati: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "menulis ke `%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "kunci %08lX: signature subkey di tempat yang salah - dilewati\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "menulis kunci rahasia ke `%s'\n"
@@ -1794,10 +1803,6 @@ msgstr "menulis kunci rahasia ke `%s'\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "kunci %08lX: kunci gaya PGP 2.x - dilewati\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "kunci %08lX: signature subkey di tempat yang salah - dilewati\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "PERINGATAN: tidak ada yang diekspor\n"
 
@@ -1917,6 +1922,11 @@ msgstr "buat sepasang kunci baru"
 msgid "quickly add a new user-id"
 msgstr "buat sepasang kunci baru"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "buat sepasang kunci baru"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2253,6 +2263,10 @@ msgstr "%s:%d: opsi impor tidak valid\n"
 msgid "invalid import options\n"
 msgstr "opsi impor tidak valid\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "opsi impor tidak valid\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: opsi ekspor tidak valid\n"
@@ -2594,6 +2608,10 @@ msgstr "perbarui database trust"
 msgid "do not update the trustdb after import"
 msgstr "perbarui database trust"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "tampilkan fingerprint"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2604,6 +2622,9 @@ msgstr "kunci rahasia tidak dapat dipakai"
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "melewati blok tipe %d\n"
@@ -2744,11 +2765,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "tidak ditemukan keyring yang dapat ditulisi: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "menulis ke `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "kesalahan menulis keyring `%s': %s\n"
@@ -3536,6 +3552,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Kunci tidak berubah sehingga tidak perlu pembaharuan.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Pembuatan kunci gagal: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "kesalahan: fingerprint tidak valid\n"
 
@@ -3867,6 +3888,10 @@ msgid "no secret key\n"
 msgstr "tidak ada kunci rahasia\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "User ID \"%s\" telah dibatalkan\n"
 
@@ -4390,10 +4415,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Keyring"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "melewati `%s': %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Fingerprint kunci primer:"
 
@@ -4513,6 +4534,10 @@ msgid "no keyserver known\n"
 msgstr "opsi ekspor tidak valid\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "melewati `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 86317d9..3a0572b 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -1793,6 +1793,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: saltata: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "scrittura in `%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "chiave %08lX: firma della subchiave nel posto sbagliato - saltata\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "scrittura della chiave segreta in `%s'\n"
@@ -1801,10 +1810,6 @@ msgstr "scrittura della chiave segreta in `%s'\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "chiave %08lX: chiave in stile PGP 2.x - saltata\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "chiave %08lX: firma della subchiave nel posto sbagliato - saltata\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "ATTENZIONE: non è stato esportato nulla\n"
 
@@ -1924,6 +1929,11 @@ msgstr "genera una nuova coppia di chiavi"
 msgid "quickly add a new user-id"
 msgstr "genera una nuova coppia di chiavi"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "genera una nuova coppia di chiavi"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2261,6 +2271,10 @@ msgstr "%s:%d: opzioni di importazione non valide\n"
 msgid "invalid import options\n"
 msgstr "opzioni di importazione non valide\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "opzioni di importazione non valide\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: opzioni di esportazione non valide\n"
@@ -2600,6 +2614,10 @@ msgstr "aggiorna il database della fiducia"
 msgid "do not update the trustdb after import"
 msgstr "aggiorna il database della fiducia"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "mostra le impronte digitali"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2610,6 +2628,9 @@ msgstr "chiave segreta inutilizzabile"
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "salto un blocco di tipo %d\n"
@@ -2750,11 +2771,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "non è stato trovato un portachiavi scrivibile: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "scrittura in `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "errore scrivendo il portachiavi `%s': %s\n"
@@ -3543,6 +3559,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "La chiave non è cambiata quindi non sono necessari aggiornamenti.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Generazione della chiave fallita: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "errore: impronta digitale non valida\n"
 
@@ -3880,6 +3901,10 @@ msgid "no secret key\n"
 msgstr "manca la chiave segreta\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "l'user ID \"%s\" è già stato revocato\n"
 
@@ -4407,10 +4432,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Portachiavi"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "saltata `%s': %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Impronta digitale della chiave primaria:"
 
@@ -4530,6 +4551,10 @@ msgid "no keyserver known\n"
 msgstr "opzioni di esportazione non valide\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "saltata `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 7f284e1..51cfc72 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -1652,6 +1652,14 @@ msgstr "エクスポートの際、できるだけ除去する"
 msgid " - skipped"
 msgstr " - スキップされました"
 
+#, c-format
+msgid "writing to '%s'\n"
+msgstr "'%s'への書き込み\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "鍵%s: 鍵はカード上にあります - スキップします\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "秘密鍵のエクスポートは認められません\n"
 
@@ -1659,10 +1667,6 @@ msgstr "秘密鍵のエクスポートは認められません\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "鍵%s: PGP 2.x形式の鍵です - スキップします\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "鍵%s: 鍵はカード上にあります - スキップします\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "*警告*: 何もエクスポートされていません\n"
 
@@ -1769,6 +1773,11 @@ msgstr "すばやく新しい鍵ペアを生成"
 msgid "quickly add a new user-id"
 msgstr "すばやく新しいユーザIDを追加"
 
+#, fuzzy
+#| msgid "quickly add a new user-id"
+msgid "quickly revoke a user-id"
+msgstr "すばやく新しいユーザIDを追加"
+
 msgid "full featured key pair generation"
 msgstr "全機能の鍵ペアを生成"
 
@@ -2080,6 +2089,11 @@ msgstr "%s:%d: 無効なインポート・オプションです\n"
 msgid "invalid import options\n"
 msgstr "無効なインポート・オプションです\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "無効な一覧オプションです\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: 無効なエクスポート・オプションです\n"
@@ -2395,6 +2409,11 @@ msgstr "インポートの際、所有者信用の値をクリアしない"
 msgid "do not update the trustdb after import"
 msgstr "インポート後、信用データベースを更新しない"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "鍵のフィンガープリントを表示"
+
 msgid "only accept updates to existing keys"
 msgstr "既存の鍵に対する更新のみ認めます"
 
@@ -2404,6 +2423,9 @@ msgstr "インポート後、利用できない部分を鍵から除去します
 msgid "remove as much as possible from key after import"
 msgstr "インポート後、できるだけ除去します"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "型%dのブロックをスキップします\n"
@@ -2545,10 +2567,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "書き込み可能な鍵リングが見つかりません: %s\n"
 
 #, c-format
-msgid "writing to '%s'\n"
-msgstr "'%s'への書き込み\n"
-
-#, c-format
 msgid "error writing keyring '%s': %s\n"
 msgstr "鍵リング'%s'の書き込みエラー: %s\n"
 
@@ -3258,6 +3276,11 @@ msgstr "更新に失敗しました: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "鍵は無変更なので更新は不要です。\n"
 
+#, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "鍵の生成に失敗しました: %s\n"
+
 #, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\"はフィンガープリントではありません\n"
@@ -3559,6 +3582,10 @@ msgid "no secret key\n"
 msgstr "秘密鍵がありません\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "ユーザID\"%s\"は、もう失効されています\n"
 
@@ -4051,10 +4078,6 @@ msgstr[0] "*警告*: %lu個の鍵がその大きさのためスキップされ
 msgid "Keyring"
 msgstr "鍵リング"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "\"%s\"をスキップしました: %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr " 主鍵フィンガープリント:"
 
@@ -4164,6 +4187,10 @@ msgid "no keyserver known\n"
 msgstr "鍵サーバがわかりません\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "\"%s\"をスキップしました: %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "鍵%sを%sへ送信\n"
 
index 9844310..db163f2 100644 (file)
--- a/po/nb.po
+++ b/po/nb.po
@@ -1,26 +1,30 @@
-# Norwegian translation (bokmål dialect) of GnuPG.
-# Copyright (C) 2004 Free Software Foundation, Inc.
+# Norwegian (bokmål) translation of Gnu Privacy Guard.
+# Copyright (C) 2016 Free Software Foundation, Inc.
 # This file is distributed under the same license as the GnuPG package.
-# Trond Endrestøl <Trond.Endrestol@fagskolen.gjovik.no>, 2004.
+# Trond Endrestøl <Trond.Endrestol@fagskolen.gjovik.no>, 2004.
+# Åka Sikrom <a4 -at- hush -dot- com>, 2016.
 #
 # Send this file to:
 # translations@gnupg.org
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gnupg 1.4.3\n"
+"Project-Id-Version: GNU gnupg 2.1.13\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2015-02-11 19:18+0100\n"
-"Last-Translator: Trond Endrestøl <Trond.Endrestol@fagskolen.gjovik.no>\n"
-"Language-Team: Norwegian Bokmål <i18n-nb@lister.ping.uio.no>\n"
+"PO-Revision-Date: 2016-07-09 22:31+0100\n"
+"Last-Translator: Åka Sikrom <a4@hush.com>\n"
+"Language-Team: Norwegian Bokmål <i18n-nb@lister.ping.uio.no>\n"
 "Language: nb\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2016-06-15 11:29+0000\n"
+"X-Generator: Poedit 1.5.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to acquire the pinentry lock: %s\n"
-msgstr "klarte ikke å lagre fingeravtrykket: %s\n"
+msgstr "klarte ikke å skaffe pin-inntastingslås: %s\n"
 
 #. TRANSLATORS: These are labels for buttons etc used in
 #. Pinentries.  An underscore indicates that the next letter
@@ -29,41 +33,36 @@ msgstr "klarte ikke 
 #. the second vertical bar.  Note that gpg-agent has been set to
 #. utf-8 so that the strings are in the expected encoding.
 msgid "|pinentry-label|_OK"
-msgstr ""
+msgstr "|pinentry-label|_OK"
 
 msgid "|pinentry-label|_Cancel"
-msgstr ""
+msgstr "|pinentry-label|_Avbryt"
 
 msgid "|pinentry-label|_Yes"
-msgstr ""
+msgstr "|pinentry-label|_Ja"
 
 msgid "|pinentry-label|_No"
-msgstr ""
+msgstr "|pinentry-label|_Nei"
 
 msgid "|pinentry-label|PIN:"
-msgstr ""
+msgstr "|pinentry-label|PIN:"
 
 msgid "|pinentry-label|_Save in password manager"
-msgstr ""
+msgstr "|pinentry-label|_Lagre i passordbehandler"
 
-#, fuzzy
-#| msgid "Do you really want to delete the selected keys? (y/N) "
 msgid "Do you really want to make your passphrase visible on the screen?"
-msgstr "Vil du virkelig slette den valgte nøkkelen? (j/N) "
+msgstr "Er du sikker på at du vil gjøre passordfrasen synlig på skjermen?"
 
 msgid "|pinentry-tt|Make passphrase visible"
-msgstr ""
+msgstr "|pinentry-tt|Gjør passordfrase synlig"
 
-#, fuzzy
-#| msgid "invalid passphrase"
 msgid "|pinentry-tt|Hide passphrase"
-msgstr "ugyldig passfrase"
+msgstr "|pinentry-tt|Skjul passordfrase"
 
 #. TRANSLATORS: This string is displayed by Pinentry as the label
 #. for the quality bar.
-#, fuzzy
 msgid "Quality:"
-msgstr "gyldighet: %s"
+msgstr "Kvalitet:"
 
 #. TRANSLATORS: This string is a tooltip, shown by pinentry when
 #. hovering over the quality bar.  Please use an appropriate
@@ -73,467 +72,437 @@ msgstr "gyldighet: %s"
 #. will be used.
 msgid "pinentry.qualitybar.tooltip"
 msgstr ""
+"Kvaliteten på teksten overfor. Spør administrator for mer informasjon om "
+"hvordan kvaliteten vurderes."
 
 msgid ""
 "Please enter your PIN, so that the secret key can be unlocked for this "
 "session"
 msgstr ""
+"Skriv inn PIN-kode slik at hemmelig nøkkel kan låses opp for denne økta"
 
 msgid ""
 "Please enter your passphrase, so that the secret key can be unlocked for "
 "this session"
 msgstr ""
+"Skriv inn passordfrasen din, slik at hemmelig nøkkel kan låses opp for "
+"gjeldende økt"
 
 msgid "PIN:"
-msgstr ""
+msgstr "PIN:"
 
-#, fuzzy
 msgid "Passphrase:"
-msgstr "ugyldig passfrase"
+msgstr "Passordfrase:"
 
 msgid "does not match - try again"
-msgstr ""
+msgstr "feil. Prøv igjen"
 
 #. TRANSLATORS: The string is appended to an error message in
 #. the pinentry.  The %s is the actual error message, the
 #. two %d give the current and maximum number of tries.
 #, c-format
 msgid "SETERROR %s (try %d of %d)"
-msgstr ""
+msgstr "SETERROR %s (forsøk %d av %d)"
 
 msgid "Repeat:"
-msgstr ""
+msgstr "Gjenta:"
 
-#, fuzzy
 msgid "PIN too long"
-msgstr "for lang linje"
+msgstr "For lang PIN"
 
-#, fuzzy
 msgid "Passphrase too long"
-msgstr "for lang linje"
+msgstr "For lang passordfrase"
 
-#, fuzzy
 msgid "Invalid characters in PIN"
-msgstr "Ugyldig tegn i navn\n"
+msgstr "Ugyldig tegn i PIN"
 
 msgid "PIN too short"
-msgstr ""
+msgstr "Koden er for kort"
 
-#, fuzzy
 msgid "Bad PIN"
-msgstr "ugyldig MPI"
+msgstr "Ugyldig PIN"
 
-#, fuzzy
 msgid "Bad Passphrase"
-msgstr "ugyldig passfrase"
+msgstr "Ugyldig passordfrase"
 
 #, c-format
 msgid "ssh keys greater than %d bits are not supported\n"
-msgstr ""
+msgstr "ssh-nøkler som er lenger enn %d bit støttes ikke\n"
 
-#, fuzzy, c-format
-#| msgid "can't create `%s': %s\n"
+#, c-format
 msgid "can't create '%s': %s\n"
-msgstr "kan ikke opprette «%s»: %s\n"
+msgstr "klarte ikke Ã¥ lage Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't open `%s': %s\n"
+#, c-format
 msgid "can't open '%s': %s\n"
-msgstr "kan ikke åpne «%s»: %s\n"
+msgstr "klarte ikke Ã¥ Ã¥pne Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting serial number of card: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av kort-serienummer: %s\n"
 
 #, c-format
 msgid "detected card with S/N: %s\n"
-msgstr ""
+msgstr "oppdaget kort med serienummer %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "no authentication key for ssh on card: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "ingen ssh-autentiseringnøkkel på kort: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "no suitable card key found: %s\n"
-msgstr "ingen skrivbart hemmelig nøkkelknippe ble funnet: %s\n"
+msgstr "fant ingen passende kortnøkkel: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "shadowing the key failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "skyggelegging av nøkkel mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error writing key: %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under skriving av nøkkel: %s\n"
 
 #, c-format
 msgid ""
 "An ssh process requested the use of key%%0A  %s%%0A  (%s)%%0ADo you want to "
 "allow this?"
 msgstr ""
+"En ssh-prosess ber om tillatelse til å brukt nøkkel%%0A  %s%%0A  (%s)%%0AVil "
+"du tillate dette?"
 
 msgid "Allow"
-msgstr ""
+msgstr "Tillat"
 
 msgid "Deny"
-msgstr ""
+msgstr "Avvis"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Please enter the passphrase for the ssh key%%0A  %F%%0A  (%c)"
-msgstr "Tast inn den nye passfrasen for denne hemmelige nøkklen.\n"
+msgstr "Skriv inn passordfrase for ssh-nøkkel%%0A  %F%%0A  (%c)"
 
-#, fuzzy
 msgid "Please re-enter this passphrase"
-msgstr "endre passfrasen"
+msgstr "Skriv inn denne passordfrasen på nytt"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Please enter a passphrase to protect the received secret key%%0A   %s%%0A   "
 "%s%%0Awithin gpg-agent's key storage"
 msgstr ""
-"Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-"\n"
+"Skriv inn passordfrase som skal brukes til å beskytte mottatt hemmelig nøkkel"
+"%%0A   %s%%0A   %s%%0Ai nøkkellageret for gpg-agent"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to create stream from socket: %s\n"
-msgstr "klarte ikke å lagre nøkkelen: %s\n"
+msgstr "klarte ikke å lage strøm av sokkel: %s\n"
 
-#, fuzzy
 msgid "Please insert the card with serial number"
-msgstr ""
-"Vennligst fjern det nåværende kortet og sett inn kortet med serienummeret:\n"
-"   %.*s\n"
+msgstr "Sett inn kort med serienummer"
 
-#, fuzzy
 msgid "Please remove the current card and insert the one with serial number"
-msgstr ""
-"Vennligst fjern det nåværende kortet og sett inn kortet med serienummeret:\n"
-"   %.*s\n"
+msgstr "Fjern gjeldende kort og sett inn kort med serienummer"
 
-#, fuzzy
 msgid "Admin PIN"
-msgstr "|A|Admin PIN"
+msgstr "Admin-PIN"
 
 #. TRANSLATORS: A PUK is the Personal Unblocking Code
 #. used to unblock a PIN.
 msgid "PUK"
-msgstr ""
+msgstr "PUK"
 
 msgid "Reset Code"
-msgstr ""
+msgstr "Tilbakestillingskode"
 
 #, c-format
 msgid "%s%%0A%%0AUse the reader's pinpad for input."
-msgstr ""
+msgstr "%s%%0A%%0ABruk leserens kodeplate til å skrive."
 
-#, fuzzy
 msgid "Repeat this Reset Code"
-msgstr "Gjenta denne PIN: "
+msgstr "Gjenta tilbakestillingskode"
 
-#, fuzzy
 msgid "Repeat this PUK"
-msgstr "Gjenta denne PIN: "
+msgstr "Gjenta PUK"
 
-#, fuzzy
 msgid "Repeat this PIN"
-msgstr "Gjenta denne PIN: "
+msgstr "Gjenta PIN"
 
-#, fuzzy
 msgid "Reset Code not correctly repeated; try again"
-msgstr "PIN ble ikke gjentatt korrekt; prøv igjen"
+msgstr "Tilbakestillingskode ble ikke gjentatt korrekt. Prøv igjen"
 
-#, fuzzy
 msgid "PUK not correctly repeated; try again"
-msgstr "PIN ble ikke gjentatt korrekt; prøv igjen"
+msgstr "PUK-kode ble ikke gjentatt korrekt. Prøv igjen"
 
 msgid "PIN not correctly repeated; try again"
-msgstr "PIN ble ikke gjentatt korrekt; prøv igjen"
+msgstr "PIN ble ikke gjentatt korrekt. Prøv igjen"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Please enter the PIN%s%s%s to unlock the card"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "Skriv inn PIN-kode%s%s%s for å låse opp kort"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error creating temporary file: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under oppretting av midlertidig fil: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error writing to temporary file: %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under skriving til midlertidig fil: %s\n"
 
-#, fuzzy
 msgid "Enter new passphrase"
-msgstr "Tast inn passfrase\n"
+msgstr "Skriv inn ny passordfrase"
 
-#, fuzzy
 msgid "Take this one anyway"
-msgstr "Bruke denne nøkkelen likevel? (j/N) "
+msgstr "Bruk denne likevel"
 
 #, c-format
 msgid ""
 "You have not entered a passphrase!%0AAn empty passphrase is not allowed."
 msgstr ""
+"Du har ikke skrevet inn en passordfrase.%0ATom passordfrase er ikke tillatt."
 
 #, c-format
 msgid ""
 "You have not entered a passphrase - this is in general a bad idea!%0APlease "
 "confirm that you do not want to have any protection on your key."
 msgstr ""
+"Du har ikke skrevet inn en passordfrase. Dette er generelt ikke lurt."
+"%0ABekreft at du ikke vil beskytte nøkkelen."
 
 msgid "Yes, protection is not needed"
-msgstr ""
+msgstr "Ja, beskyttelse er unødvendig"
 
-#, fuzzy, c-format
-#| msgid "Name must be at least 5 characters long\n"
+#, c-format
 msgid "A passphrase should be at least %u character long."
 msgid_plural "A passphrase should be at least %u characters long."
-msgstr[0] "Navnet må være minst 5 tegn langt\n"
-msgstr[1] "Navnet må være minst 5 tegn langt\n"
+msgstr[0] "Passordfraser skal bestå av minst %u tegn."
+msgstr[1] "Passordfraser skal bestå av minst %u tegn."
 
 #, c-format
 msgid "A passphrase should contain at least %u digit or%%0Aspecial character."
 msgid_plural ""
 "A passphrase should contain at least %u digits or%%0Aspecial characters."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Passordfraser bør inneholde minst %u siffer eller%%0Aspesialtegn."
+msgstr[1] "Passordfraser bør inneholde minst %u sifre eller%%0Aspesialtegn."
 
 #, c-format
 msgid "A passphrase may not be a known term or match%%0Acertain pattern."
-msgstr ""
+msgstr "Ikke bruk kjente ord, uttrykk eller kjente mønster%%0Ai passordfraser."
 
 msgid "Warning: You have entered an insecure passphrase."
-msgstr ""
+msgstr "Advarsel: du har skrevet inn en svak passordfrase."
 
-#, fuzzy, c-format
+#, c-format
 msgid "Please enter the passphrase to%0Aprotect your new key"
-msgstr ""
-"Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-"\n"
+msgstr "Skriv inn passordfrase for å%0Abeskytte ny nøkkel"
 
-#, fuzzy
 msgid "Please enter the new passphrase"
-msgstr "endre passfrasen"
+msgstr "Skriv inn ny passordfrase"
 
-#, fuzzy
 msgid ""
 "@Options:\n"
 " "
 msgstr ""
-"@\n"
-"Valg:\n"
+"@Valg:\n"
 " "
 
 msgid "run in daemon mode (background)"
-msgstr ""
+msgstr "kjør som bakgrunnsprosess («daemon»)"
 
 msgid "run in server mode (foreground)"
-msgstr ""
+msgstr "kjør i tjenermodus (forgrunn)"
 
 msgid "verbose"
-msgstr "fyldig output"
+msgstr "detaljert utskrift"
 
 msgid "be somewhat more quiet"
-msgstr "være noenlunde stille"
+msgstr "være noenlunde stille"
 
 msgid "sh-style command output"
-msgstr ""
+msgstr "sh-utdata for kommandoer"
 
 msgid "csh-style command output"
-msgstr ""
+msgstr "csh-utdata for kommandoer"
 
-#, fuzzy
 msgid "|FILE|read options from FILE"
-msgstr "leser valg fra «%s»\n"
+msgstr "|FIL|les valg fra valgt FIL"
 
 msgid "do not detach from the console"
-msgstr ""
+msgstr "ikke løsne fra konsoll"
 
 msgid "do not grab keyboard and mouse"
-msgstr ""
+msgstr "ikke bruk tastatur og mus"
 
-#, fuzzy
 msgid "use a log file for the server"
-msgstr "søke etter nøkler på en nøkkelserver"
+msgstr "bruk loggfil for tjeneren"
 
 msgid "|PGM|use PGM as the PIN-Entry program"
-msgstr ""
+msgstr "|PGM|bruk PGM til inntasting av PIN-koder"
 
 msgid "|PGM|use PGM as the SCdaemon program"
-msgstr ""
+msgstr "|PGM|bruk PGN som SCdaemon-program"
 
-#, fuzzy
 msgid "do not use the SCdaemon"
-msgstr "ikke oppdatér tillitsdatabasen etter import"
+msgstr "ikke bruk SCdaemon"
 
-#, fuzzy
 msgid "|NAME|accept some commands via NAME"
-msgstr "|NAVN|kryptere for NAVN"
+msgstr "|NAME|godta enkelte kommandoer via «NAME»"
 
 msgid "ignore requests to change the TTY"
-msgstr ""
+msgstr "ignorer forespørsler om å bytte TTY"
 
 msgid "ignore requests to change the X display"
-msgstr ""
+msgstr "ignorer forespørsler om å bytte X-skjerm"
 
 msgid "|N|expire cached PINs after N seconds"
-msgstr ""
+msgstr "|N|fjern hurtiglagrede PIN-koder etter N sekunder"
 
 msgid "do not use the PIN cache when signing"
-msgstr ""
+msgstr "ikke bruk PIN-hurtiglager under signering"
 
-#, fuzzy
 msgid "disallow the use of an external password cache"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "ikke tillat bruk av eksternt passord-hurtiglager"
 
 msgid "disallow clients to mark keys as \"trusted\""
-msgstr ""
+msgstr "ikke la klienter tillitsmarkere nøkler"
 
-#, fuzzy
 msgid "allow presetting passphrase"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "tillat valg av passordfrase på forhånd"
 
 msgid "disallow caller to override the pinentry"
-msgstr ""
+msgstr "ikke la kaller overstyre PIN-inntasting"
 
 msgid "allow passphrase to be prompted through Emacs"
-msgstr ""
+msgstr "la brukeren skrive inn passordfrase via Emacs"
 
 msgid "enable ssh support"
-msgstr ""
+msgstr "slå på ssh-støtte"
 
 msgid "enable putty support"
-msgstr ""
+msgstr "slå på støtte for putty"
 
 #. TRANSLATORS: @EMAIL@ will get replaced by the actual bug
 #. reporting address.  This is so that we can change the
 #. reporting address without breaking the translations.
-#, fuzzy
 msgid "Please report bugs to <@EMAIL@>.\n"
-msgstr "Vennligst rapporter feil til <gnupg-bugs@gnu.org>.\n"
+msgstr "Rapporter programfeil til <@EMAIL@>.\n"
 
-#, fuzzy
 msgid "Usage: @GPG_AGENT@ [options] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: @GPG_AGENT@ [valg] («-h» for hjelp)"
 
 msgid ""
 "Syntax: @GPG_AGENT@ [options] [command [args]]\n"
 "Secret key management for @GNUPG@\n"
 msgstr ""
+"Syntaks: @GPG_AGENT@ [valg] [kommando [arg]]\n"
+"Håndtering av hemmelige nøkler for @GNUPG@\n"
 
 #, c-format
 msgid "invalid debug-level '%s' given\n"
-msgstr ""
+msgstr "«%s» er et ugyldig feilsøkingsnivå\n"
 
 #, c-format
 msgid "%s is too old (need %s, have %s)\n"
-msgstr ""
+msgstr "%s er for gammel (krever %s, har %s)\n"
 
-#, fuzzy, c-format
-#| msgid "NOTE: no default option file `%s'\n"
+#, c-format
 msgid "Note: no default option file '%s'\n"
-msgstr "MERK: ingen standard valgfil «%s»\n"
+msgstr "Merk: standardvalg-fil «%s» finnes ikke\n"
 
-#, fuzzy, c-format
-#| msgid "option file `%s': %s\n"
+#, c-format
 msgid "option file '%s': %s\n"
-msgstr "valgfil «%s»: %s\n"
+msgstr "valgfil Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "reading options from `%s'\n"
+#, c-format
 msgid "reading options from '%s'\n"
-msgstr "leser valg fra «%s»\n"
+msgstr "leser valg fra Â«%s»\n"
 
 #, c-format
 msgid "Note: '%s' is not considered an option\n"
-msgstr ""
+msgstr "Merk: «%s» regnes ikke som et valg\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't create socket: %s\n"
-msgstr "kan ikke opprette «%s»: %s\n"
+msgstr "klarte ikke å lage sokkel: %s\n"
 
 #, c-format
 msgid "socket name '%s' is too long\n"
-msgstr ""
+msgstr "sokkelnavnet «%s» er for langt\n"
 
 msgid "a gpg-agent is already running - not starting a new one\n"
-msgstr ""
+msgstr "en gpg-agent kjører allerede. Lar være å starte en ny\n"
 
-#, fuzzy
 msgid "error getting nonce for the socket\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av sokkel-anledning\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error binding socket to '%s': %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under knytning av sokkel til Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't set permissions of '%s': %s\n"
-msgstr "ADVARSEL: utrygge rettigheter på utvidelsen «%s»\n"
+msgstr "klarte ikke å endre tillatelser til «%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "listen() failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "listen() mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "listening on socket '%s'\n"
-msgstr "skriver hemmelig nøkkel til «%s»\n"
+msgstr "lytter pÃ¥ sokkel Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "can't create directory `%s': %s\n"
+#, c-format
 msgid "can't create directory '%s': %s\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "klarte ikke Ã¥ lage mappa Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "directory `%s' created\n"
+#, c-format
 msgid "directory '%s' created\n"
-msgstr "katalogen «%s» ble opprettet\n"
+msgstr "mappa «%s» er opprettet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "stat() failed for '%s': %s\n"
-msgstr "fstat(%d) mislyktes in %s: %s\n"
+msgstr "stat() mislyktes for «%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't use '%s' as home directory\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "«%s» kan ikke brukes som hjemmemappe\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading nonce on fd %d: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av anledning på fd %d: %s\n"
 
 #, c-format
 msgid "handler 0x%lx for fd %d started\n"
-msgstr ""
+msgstr "startet behandler 0x%lx for fd %d\n"
 
 #, c-format
 msgid "handler 0x%lx for fd %d terminated\n"
-msgstr ""
+msgstr "avsluttet behandler 0x%lx for fd %d\n"
 
 #, c-format
 msgid "ssh handler 0x%lx for fd %d started\n"
-msgstr ""
+msgstr "startet ssh-behandler 0x%lx for fd %d\n"
 
 #, c-format
 msgid "ssh handler 0x%lx for fd %d terminated\n"
-msgstr ""
+msgstr "avsluttet ssh-behandler 0x%lx for fd %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "npth_pselect failed: %s - waiting 1s\n"
-msgstr "oppdatering av hemmelig mislyktes: %s\n"
+msgstr "npth_pselect mislyktes: %s - venter 1s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s %s stopped\n"
-msgstr "%s: hoppet over: %s\n"
+msgstr "%s %s stoppet\n"
 
 msgid "no gpg-agent running in this session\n"
-msgstr ""
+msgstr "ingen gpg-agent kjører i gjeldende økt\n"
 
-#, fuzzy
 msgid "Usage: gpg-preset-passphrase [options] KEYGRIP (-h for help)\n"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: gpg-preset-passphrase [valg] NØKKELGREP («-h» for hjelp)\n"
 
 msgid ""
 "Syntax: gpg-preset-passphrase [options] KEYGRIP\n"
 "Password cache maintenance\n"
 msgstr ""
+"Syntaks: gpg-preset-passphrase [valg] KEYGRIP\n"
+"Vedlikehold av hurtiglager for passord\n"
 
 msgid ""
 "@Commands:\n"
@@ -551,69 +520,72 @@ msgstr ""
 "Valg:\n"
 " "
 
-#, fuzzy
 msgid "Usage: gpg-protect-tool [options] (-h for help)\n"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: gpg-protect-tool [valg] («-h» for hjelp)\n"
 
 msgid ""
 "Syntax: gpg-protect-tool [options] [args]\n"
 "Secret key maintenance tool\n"
 msgstr ""
+"Syntaks: gpg-protect-tool [valg] [arg]\n"
+"Håndteringsverktøy for hemmelige nøkler\n"
 
 msgid "Please enter the passphrase to unprotect the PKCS#12 object."
-msgstr ""
+msgstr "Skriv inn passordfrase for å låse opp PKCS#12-objekt."
 
 msgid "Please enter the passphrase to protect the new PKCS#12 object."
-msgstr ""
+msgstr "Skriv inn passordfrase for å låse nytt PKCS#12-objekt."
 
 msgid ""
 "Please enter the passphrase to protect the imported object within the GnuPG "
 "system."
 msgstr ""
+"Skriv inn passordfrase for å låse nytt importert objekt i GnuPG-systemet."
 
 msgid ""
 "Please enter the passphrase or the PIN\n"
 "needed to complete this operation."
 msgstr ""
+"Skriv inn passordfrase eller PIN-kode som\n"
+"\vkreves for å fullføre gjeldende handling."
 
-#, fuzzy
 msgid "cancelled\n"
-msgstr "cancel|cancel"
+msgstr "avbrutt\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error while asking for the passphrase: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under spørring etter passordfrase: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error opening '%s': %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under Ã¥pning av Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "file '%s', line %d: %s\n"
-msgstr "valgfil «%s»: %s\n"
+msgstr "fil «%s», linje %d: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "statement \"%s\" ignored in '%s', line %d\n"
-msgstr "lesefeil ved «%s»: %s\n"
+msgstr "uttrykk «%s» ignorert i «%s», linje %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "system trustlist '%s' not available\n"
-msgstr "hemmelig nøkkel er ikke tilgjengelig"
+msgstr "system-tillitsliste «%s» er ikke tilgjengelig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad fingerprint in '%s', line %d\n"
-msgstr "lesefeil ved «%s»: %s\n"
+msgstr "ugyldig fingeravtrykk i «%s», linje %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid keyflag in '%s', line %d\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "ugyldig nøkkelvalg i «%s», linje %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading '%s', line %d: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av «%s», linje %d: %s\n"
 
 msgid "error reading list of trusted root certificates\n"
-msgstr ""
+msgstr "feil under lesing av liste over tillitsmerkede rotsertifikater\n"
 
 #. TRANSLATORS: This prompt is shown by the Pinentry
 #. and has one special property: A "%%0A" is used by
@@ -628,13 +600,14 @@ msgid ""
 "Do you ultimately trust%%0A  \"%s\"%%0Ato correctly certify user "
 "certificates?"
 msgstr ""
+"Stoler du fullstendig på at%%0A  «%s»%%0Asertifiserer brukersertifikater "
+"korrekt?"
 
-#, fuzzy
 msgid "Yes"
-msgstr "ja"
+msgstr "Ja"
 
 msgid "No"
-msgstr ""
+msgstr "Nei"
 
 #. TRANSLATORS: This prompt is shown by the Pinentry and has
 #. one special property: A "%%0A" is used by Pinentry to
@@ -648,149 +621,152 @@ msgstr ""
 msgid ""
 "Please verify that the certificate identified as:%%0A  \"%s\"%%0Ahas the "
 "fingerprint:%%0A  %s"
-msgstr ""
+msgstr "Kontroller at sertifikatet%%0A  «%s»%%0Ahar fingeravtrykket%%0A  %s"
 
 #. TRANSLATORS: "Correct" is the label of a button and intended
 #. to be hit if the fingerprint matches the one of the CA.  The
 #. other button is "the default "Cancel" of the Pinentry.
 msgid "Correct"
-msgstr ""
+msgstr "Riktig"
 
 msgid "Wrong"
-msgstr ""
+msgstr "Feil"
 
 #, c-format
 msgid "Note: This passphrase has never been changed.%0APlease change it now."
 msgstr ""
+"Merk: denne passordfrasen har aldri blitt endret.%0AEndre den umiddelbart."
 
 #, c-format
 msgid ""
 "This passphrase has not been changed%%0Asince %.4s-%.2s-%.2s.  Please change "
 "it now."
 msgstr ""
+"Denne passordfrasen har ikke blitt endret%%0Asiden %.4s-%.2s-%.2s. Endre den "
+"umiddelbart."
 
-#, fuzzy
 msgid "Change passphrase"
-msgstr "endre passfrasen"
+msgstr "Endre passordfrase"
 
 msgid "I'll change it later"
-msgstr ""
+msgstr "Jeg endrer senere"
 
-#, fuzzy, c-format
-#| msgid "Do you really want to delete the selected keys? (y/N) "
+#, c-format
 msgid ""
 "Do you really want to delete the key identified by keygrip%%0A  %s%%0A  %%C"
 "%%0A?"
-msgstr "Vil du virkelig slette den valgte nøkkelen? (j/N) "
+msgstr ""
+"Er du sikker på at du vil slette nøkkel med nøkkelgrep%%0A  %s%%0A  %%C%%0A?"
 
-#, fuzzy
-#| msgid "enable key"
 msgid "Delete key"
-msgstr "innkoble en nøkkel"
+msgstr "Slett nøkkel"
 
 msgid ""
 "Warning: This key is also listed for use with SSH!\n"
 "Deleting the key might remove your ability to access remote machines."
 msgstr ""
+"Advarsel: denne nøkkelen brukes også som SSH-nøkkel.\n"
+"Hvis du sletter nøkkelen, kan du miste tilgang til én eller flere eksterne "
+"maskiner."
 
 msgid "DSA requires the hash length to be a multiple of 8 bits\n"
-msgstr ""
+msgstr "DSA krever at kontrollsummen er multipliserbar med 8 bit\n"
 
 #, c-format
 msgid "%s key uses an unsafe (%u bit) hash\n"
-msgstr ""
+msgstr "%s nøkkel bruker utrygg kontrollsum (%u bit)\n"
 
 #, c-format
 msgid "a %zu bit hash is not valid for a %u bit %s key\n"
-msgstr ""
+msgstr "kontrollsum på %zu bit er ugyldig for %u-bits %s-nøkler\n"
 
 #, c-format
 msgid "checking created signature failed: %s\n"
-msgstr ""
+msgstr "kontroll av opprettet signatur mislyktes. %s\n"
 
 msgid "secret key parts are not available\n"
-msgstr ""
+msgstr "hemmelige nøkkeldeler er ikke tilgjenglig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "public key algorithm %d (%s) is not supported\n"
-msgstr "ikke støttet"
+msgstr "offentlig nøkkelalgoritme %d (%s) støttes ikke\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "protection algorithm %d (%s) is not supported\n"
-msgstr "kryptert med en ukjent algoritme %d\n"
+msgstr "beskyttelsesalgoritme %d (%s) støttes ikke\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "protection hash algorithm %d (%s) is not supported\n"
-msgstr "ikke støttet"
+msgstr "kontrollsum-algoritme for beskyttelse %d (%s) støttes ikke\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error creating a pipe: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under opprettelse av datarør: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error creating a stream for a pipe: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under opprettelse av strøm for datarør: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error forking process: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under kopiering av prosess: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "waiting for processes to terminate failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "venting på avslutning av prosesser mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error running '%s': probably not installed\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr ""
+"feil under kjøring av «%s». Programmet er sannsynligvis ikke installert\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error running '%s': exit status %d\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under kjøring av «%s». Avslutningskode %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error running '%s': terminated\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under kjøring av «%s». Avsluttet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting exit code of process %d: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under henting av avslutningskode for prosess %d: %s\n"
 
 #, c-format
 msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+msgstr "prosessen %d avsluttet ikke i tide. %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't close `%s': %s\n"
+#, c-format
 msgid "can't connect to '%s': %s\n"
-msgstr "kan ikke lukke «%s»: %s\n"
+msgstr "klarte ikke Ã¥ koble til Â«%s»: %s\n"
 
 msgid "communication problem with gpg-agent\n"
-msgstr ""
+msgstr "kommunikasjonsproblemer med gpg-agent\n"
 
 msgid "problem setting the gpg-agent options\n"
-msgstr ""
+msgstr "klarte ikke å sette opp valg for gpg-agent\n"
 
 msgid "canceled by user\n"
-msgstr ""
+msgstr "avbrutt av bruker\n"
 
 msgid "problem with the agent\n"
-msgstr ""
+msgstr "problemer med agent\n"
 
 #, c-format
 msgid "problem with the agent (unexpected response \"%s\")\n"
-msgstr ""
+msgstr "problemer med agent (uventet svar: «%s»)\n"
 
 #, c-format
 msgid "can't disable core dumps: %s\n"
-msgstr ""
+msgstr "klarte ikke å slå av kjernedump: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Warning: unsafe ownership on %s \"%s\"\n"
-msgstr "ADVARSEL: utrygt eierskap på utvidelsen «%s»\n"
+msgstr "Advarsel: utrygt eierskap til %s Â«%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgstr "ADVARSEL: utrygge rettigheter på utvidelsen «%s»\n"
+msgstr "Advarsel: utrygge tillatelser til %s Â«%s»\n"
 
 #. TRANSLATORS: See doc/TRANSLATE about this string.
 msgid "yes"
@@ -829,330 +805,292 @@ msgstr "cC"
 
 #, c-format
 msgid "out of core in secure memory while allocating %lu bytes"
-msgstr ""
+msgstr "kjernen i sikkert minne ble full under tildeling av %lu byte"
 
 #, c-format
 msgid "out of core while allocating %lu bytes"
-msgstr ""
+msgstr "kjernen ble full under tildeling av %lu byte"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error allocating enough memory: %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "feil under tildeling av minne. %s\n"
 
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
-msgstr ""
+msgstr "%s:%u: valget «%s» er utgått, og har nå ingen effekt\n"
 
 #, c-format
 msgid "WARNING: \"%s%s\" is an obsolete option - it has no effect\n"
-msgstr ""
+msgstr "ADVARSEL: valget «%s%s» er utgått, og har ingen effekt\n"
 
 #, c-format
 msgid "unknown debug flag '%s' ignored\n"
-msgstr ""
+msgstr "unknown debug flag '%s' ignored\n"
 
 #, c-format
 msgid "no running gpg-agent - starting '%s'\n"
-msgstr ""
+msgstr "ingen kjørende gpg-agent. Starter «%s»\n"
 
 #, c-format
 msgid "waiting for the agent to come up ... (%ds)\n"
-msgstr ""
+msgstr "venter på at agent skal dukke opp … (%ds)\n"
 
 msgid "connection to agent established\n"
-msgstr ""
+msgstr "koblet til agent\n"
 
-#, fuzzy
-#| msgid "can't do this in batch mode\n"
 msgid "connection to agent is in restricted mode\n"
-msgstr "kan ikke gjøre dette i batchmodus\n"
+msgstr "kobler til agent i begrenset modus\n"
 
 #, c-format
 msgid "no running Dirmngr - starting '%s'\n"
-msgstr ""
+msgstr "ingen kjørende Dirmngr. Starter «%s»\n"
 
 #, c-format
 msgid "waiting for the dirmngr to come up ... (%ds)\n"
-msgstr ""
+msgstr "venter på at dirmngr skal dukke opp … (%ds)\n"
 
 msgid "connection to the dirmngr established\n"
-msgstr ""
+msgstr "koblet til dirmngr\n"
 
 #. TRANSLATORS: Copy the prefix between the vertical bars
 #. verbatim.  It will not be printed.
 msgid "|audit-log-result|Good"
-msgstr ""
+msgstr "|audit-log-result|Bra"
 
 msgid "|audit-log-result|Bad"
-msgstr ""
+msgstr "|audit-log-result|Dårlig"
 
 msgid "|audit-log-result|Not supported"
-msgstr ""
+msgstr "|audit-log-result|Støttes ikke"
 
-#, fuzzy
 msgid "|audit-log-result|No certificate"
-msgstr "ugyldig sertifikat"
+msgstr "|audit-log-result|Ingen sertifikat"
 
-#, fuzzy
 msgid "|audit-log-result|Not enabled"
-msgstr "ugyldig sertifikat"
+msgstr "|audit-log-result|Ikke i bruk"
 
 msgid "|audit-log-result|Error"
-msgstr ""
+msgstr "|audit-log-result|Feil"
 
-#, fuzzy
 msgid "|audit-log-result|Not used"
-msgstr "ugyldig sertifikat"
+msgstr "|audit-log-result|Ikke brukt"
 
-#, fuzzy
 msgid "|audit-log-result|Okay"
-msgstr "ugyldig sertifikat"
+msgstr "|audit-log-result|Ok"
 
-#, fuzzy
 msgid "|audit-log-result|Skipped"
-msgstr "ugyldig sertifikat"
+msgstr "|audit-log-result|Hoppet over"
 
-#, fuzzy
 msgid "|audit-log-result|Some"
-msgstr "ugyldig sertifikat"
+msgstr "|audit-log-result|Noe"
 
-#, fuzzy
 msgid "Certificate chain available"
-msgstr "ugyldig sertifikat"
+msgstr "Sertifikatkjede tilgjengelig"
 
-#, fuzzy
 msgid "root certificate missing"
-msgstr "ugyldig sertifikat"
+msgstr "rotsertifikat mangler"
 
 msgid "Data encryption succeeded"
-msgstr ""
+msgstr "Datakryptering fullført"
 
-#, fuzzy
 msgid "Data available"
-msgstr "vis alle tilgjengelige data"
+msgstr "Data tilgjengelig"
 
-#, fuzzy
 msgid "Session key created"
-msgstr "nøkkelknippet «%s» ble opprettet\n"
+msgstr "Øktnøkkel opprettet"
 
-#, fuzzy, c-format
+#, c-format
 msgid "algorithm: %s"
-msgstr "gyldighet: %s"
+msgstr "algoritme: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unsupported algorithm: %s"
-msgstr ""
-"\n"
-"Støttede algoritmer:\n"
+msgstr "ustøttet algoritme: %s"
 
-#, fuzzy
 msgid "seems to be not encrypted"
-msgstr "ikke kryptert"
+msgstr "ser ikke ut til å være kryptert"
 
 msgid "Number of recipients"
-msgstr ""
+msgstr "Antall mottakere"
 
 #, c-format
 msgid "Recipient %d"
-msgstr ""
+msgstr "Mottaker %d"
 
 msgid "Data signing succeeded"
-msgstr ""
+msgstr "Datasignering fullført"
 
-#, fuzzy, c-format
+#, c-format
 msgid "data hash algorithm: %s"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "summeringsalgoritme for data: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Signer %d"
-msgstr "Signatur opprettet %s\n"
+msgstr "Undertegnet %d"
 
-#, fuzzy, c-format
+#, c-format
 msgid "attr hash algorithm: %s"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "summeringsalgoritme for attributter: %s"
 
 msgid "Data decryption succeeded"
-msgstr ""
+msgstr "Datadekryptering fullført"
 
-#, fuzzy
 msgid "Encryption algorithm supported"
-msgstr "kryptert med en ukjent algoritme %d\n"
+msgstr "Krypteringsalgoritme støttes"
 
 msgid "Data verification succeeded"
-msgstr ""
+msgstr "Databekreftelse vellykket"
 
-#, fuzzy
 msgid "Signature available"
-msgstr "Signatur opprettet %s\n"
+msgstr "Signatur tilgjengelig"
 
-#, fuzzy
 msgid "Parsing data succeeded"
-msgstr "ingen signatur ble funnet\n"
+msgstr "Datatolkning fullført"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad data hash algorithm: %s"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "ugyldig summeringsalgoritme for data: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Signature %d"
-msgstr "Signatur opprettet %s\n"
+msgstr "Signatur %d"
 
-#, fuzzy
 msgid "Certificate chain valid"
-msgstr "Denne nøkkelen er utgått!"
+msgstr "Sertifikatkjede gyldig"
 
-#, fuzzy
 msgid "Root certificate trustworthy"
-msgstr "ugyldig sertifikat"
+msgstr "Rotsertifikat regnes som troverdig"
 
-#, fuzzy
 msgid "no CRL found for certificate"
-msgstr "ugyldig sertifikat"
+msgstr "fant ingen sertifikat-CRL"
 
-#, fuzzy
 msgid "the available CRL is too old"
-msgstr "Nøkkel tilgjengelig ved: "
+msgstr "tilgjengelig CRL er for gammel"
 
-#, fuzzy
 msgid "CRL/OCSP check of certificates"
-msgstr "ugyldig sertifikat"
+msgstr "CRL-/OCSP-sertifikatkontroll"
 
-#, fuzzy
 msgid "Included certificates"
-msgstr "ugyldig sertifikat"
+msgstr "Inkluderte sertifikater"
 
 msgid "No audit log entries."
-msgstr ""
+msgstr "Ingen elementer i revisjonslogg."
 
-#, fuzzy
 msgid "Unknown operation"
-msgstr "ukjent versjon"
+msgstr "Ukjent handling"
 
 msgid "Gpg-Agent usable"
-msgstr ""
+msgstr "Gpg-Agent kan brukes"
 
 msgid "Dirmngr usable"
-msgstr ""
+msgstr "Dirmngr kan brukes"
 
 #, c-format
 msgid "No help available for '%s'."
-msgstr ""
+msgstr "Ingen hjelp tilgjengelig for «%s»"
 
-#, fuzzy
 msgid "ignoring garbage line"
-msgstr "feil i trailerlinje\n"
+msgstr "ignorerer ubrukelig linje"
 
-#, fuzzy
 msgid "[none]"
-msgstr "[ikke satt]"
+msgstr "[ingen]"
 
-#, fuzzy
 msgid "argument not expected"
-msgstr "Admin-kommandoer er ikke tillatt\n"
+msgstr "uforventet argument"
 
-#, fuzzy
 msgid "read error"
-msgstr "feil ved lesing av fil"
+msgstr "lesefeil"
 
-#, fuzzy
 msgid "keyword too long"
-msgstr "for lang linje"
+msgstr "nøkkelord er for langt"
 
-#, fuzzy
 msgid "missing argument"
-msgstr "ugydig argument"
+msgstr "argument mangler"
 
-#, fuzzy
-#| msgid "invalid armor"
 msgid "invalid argument"
-msgstr "ugyldig beskyttelse"
+msgstr "ugydig argument"
 
-#, fuzzy
 msgid "invalid command"
-msgstr "Admin-reservert kommando\n"
+msgstr "ugyldig kommando"
 
-#, fuzzy
 msgid "invalid alias definition"
-msgstr "ugyldige listevalg\n"
+msgstr "ugyldig aliasdefinisjon"
 
-#, fuzzy
 msgid "out of core"
-msgstr "ikke tvunget"
+msgstr "kjernen er full"
 
-#, fuzzy
 msgid "invalid option"
-msgstr "ugyldige listevalg\n"
+msgstr "ugyldig valg"
 
 #, c-format
 msgid "missing argument for option \"%.50s\"\n"
-msgstr ""
+msgstr "valget «%.50s» mangler et argument\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid argument for option \"%.50s\"\n"
-msgstr "ugyldige listevalg\n"
+msgstr "ugyldig argument for valget «%.50s»\n"
 
 #, c-format
 msgid "option \"%.50s\" does not expect an argument\n"
-msgstr ""
+msgstr "valget «%.50s» skal ikke brukes med argumenter\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid command \"%.50s\"\n"
-msgstr "Ugyldig kommando  (prøv «help»)\n"
+msgstr "kommandoen «%.50s» er ugyldig\n"
 
 #, c-format
 msgid "option \"%.50s\" is ambiguous\n"
-msgstr ""
+msgstr "valget «%.50s» er flertydig\n"
 
 #, c-format
 msgid "command \"%.50s\" is ambiguous\n"
-msgstr ""
+msgstr "kommandoen «%.50s» er flertydig\n"
 
-#, fuzzy
 msgid "out of core\n"
-msgstr "ikke tvunget"
+msgstr "kjernen er full\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid option \"%.50s\"\n"
-msgstr "ugyldige listevalg\n"
+msgstr "valget «%.50s» er ugyldig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "konvertering fra «%s» til «%s» er ikke tilgjengelig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "iconv_open failed: %s\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "iconv_open mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "conversion from '%s' to '%s' failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "konvertering fra Â«%s» til Â«%s» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to create temporary file '%s': %s\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "klarte ikke Ã¥ lage midlertidig fil Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error writing to '%s': %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under skriving til Â«%s»: %s\n"
 
 #, c-format
 msgid "removing stale lockfile (created by %d)\n"
-msgstr ""
+msgstr "fjerner ødelagt låsfil (laget av %d)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "waiting for lock (held by %d%s) %s...\n"
-msgstr "venter på låsing av «%s» ...\n"
+msgstr "venter på lås (holdt igjen av %d%s) %s …\n"
 
 msgid "(deadlock?) "
-msgstr ""
+msgstr "(vranglås?) "
 
-#, fuzzy, c-format
+#, c-format
 msgid "lock '%s' not made: %s\n"
-msgstr "fant ikke offentlig nøkkel %s: %s\n"
+msgstr "lås «%s» ikke opprettet: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "waiting for lock %s...\n"
-msgstr "venter på låsing av «%s» ...\n"
+msgstr "venter på lås %s …\n"
 
 #, c-format
 msgid "armor: %s\n"
@@ -1167,15 +1105,14 @@ msgstr "armorheader: "
 msgid "invalid clearsig header\n"
 msgstr "ugyldig clearsigheader\n"
 
-#, fuzzy
 msgid "unknown armor header: "
-msgstr "armorheader: "
+msgstr "ukjent skjold-hode: "
 
 msgid "nested clear text signatures\n"
-msgstr "nøstede klartekstsignaturer\n"
+msgstr "nøstede klartekst-signaturer\n"
 
 msgid "unexpected armor: "
-msgstr "uforventet armering:"
+msgstr "uforventet armering: "
 
 msgid "invalid dash escaped line: "
 msgstr "ugyldig bindestrekbeskyttet linje: "
@@ -1191,20 +1128,20 @@ msgid "premature eof (in CRC)\n"
 msgstr "for tidlig eof (i CRC)\n"
 
 msgid "malformed CRC\n"
-msgstr "misdannet CRC\n"
+msgstr "feilformatert CRC\n"
 
 #, c-format
 msgid "CRC error; %06lX - %06lX\n"
 msgstr "CRC-feil; %06lX - %06lX\n"
 
 msgid "premature eof (in trailer)\n"
-msgstr "for tidlig eof (i trailer)\n"
+msgstr "for tidlig eof (på sluttlinje)\n"
 
 msgid "error in trailer line\n"
-msgstr "feil i trailerlinje\n"
+msgstr "feil på etterfølgende linje\n"
 
 msgid "no valid OpenPGP data found.\n"
-msgstr "ingen gyldig OpenPGP-data funnet.\n"
+msgstr "fant ingen gyldig OpenPGP-data.\n"
 
 #, c-format
 msgid "invalid armor: line longer than %d characters\n"
@@ -1213,80 +1150,79 @@ msgstr "ugyldig armor: linje lengre enn %d tegn\n"
 msgid ""
 "quoted printable character in armor - probably a buggy MTA has been used\n"
 msgstr ""
-"quoted printable-tegn i armor - antakelig har en MTA med feil blitt brukt\n"
+"anført utskrivbart tegn i armor. Noen har antakeligvis brukt en feiloppsatt "
+"e-posttjener\n"
 
 #, c-format
 msgid "[ not human readable (%zu bytes: %s%s) ]"
-msgstr ""
+msgstr "[ ikke menneskevennlig (%zu byte: %s%s) ]"
 
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
 msgstr ""
+"notatnavn kan bare inneholde utskrivbare tegn og mellomrom, og må slutte med "
+"«=»\n"
 
 msgid "a user notation name must contain the '@' character\n"
-msgstr ""
+msgstr "bruker-notatnavn må inneholde tegnet «@»\n"
 
 msgid "a notation name must not contain more than one '@' character\n"
-msgstr ""
+msgstr "notatnavn kan ikke inneholde flere enn ett «@»-tegn\n"
 
 msgid "a notation value must not use any control characters\n"
-msgstr ""
+msgstr "notatverdier kan ikke inneholde kontrolltegn\n"
 
 msgid "a notation name may not contain an '=' character\n"
-msgstr ""
+msgstr "notatnavn kan ikke inneholde tegnet «=»\n"
 
 msgid "a notation name must have only printable characters or spaces\n"
-msgstr ""
+msgstr "notatnavn skal bare inneholde utskrivbare tegn og evt. mellomrom\n"
 
-#, fuzzy
 msgid "WARNING: invalid notation data found\n"
-msgstr "ingen gyldig OpenPGP-data funnet.\n"
+msgstr "ADVARSEL: fant ugyldig notatdata\n"
 
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
-msgstr ""
+msgstr "klarte ikke å videresende %s forespørsel til klient\n"
 
 msgid "Enter passphrase: "
-msgstr "Tast inn passfrase: "
+msgstr "Skriv inn passordfrase: "
 
-#, fuzzy, c-format
-#| msgid "error creating keyring `%s': %s\n"
+#, c-format
 msgid "error getting version from '%s': %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "feil under henting av versjon fra Â«%s»: %s\n"
 
 #, c-format
 msgid "server '%s' is older than us (%s < %s)"
-msgstr ""
+msgstr "tjener «%s» er eldre enn oss (%s < %s)"
 
-#, fuzzy, c-format
-#| msgid "WARNING: %s overrides %s\n"
+#, c-format
 msgid "WARNING: %s\n"
-msgstr "ADVARSEL: %s overstyrere %s\n"
+msgstr "ADVARSEL: %s\n"
 
 #, c-format
 msgid "OpenPGP card not available: %s\n"
-msgstr "OpenPGP-kort er ikke tilgjengelig: %s\n"
+msgstr "OpenPGP-kort er ikke tilgjengelig. %s\n"
 
 #, c-format
 msgid "OpenPGP card no. %s detected\n"
 msgstr "OpenPGP-kortnummer %s oppdaget\n"
 
 msgid "can't do this in batch mode\n"
-msgstr "kan ikke gjøre dette i batchmodus\n"
+msgstr "du kan ikke gjøres dette i buntmodus\n"
 
-#, fuzzy
 msgid "This command is only available for version 2 cards\n"
-msgstr "Denne kommandoen er ikke tillatt i %s-modus.\n"
+msgstr "Denne kommandoen er bare tilgjengelig for kort av versjon 2\n"
 
 msgid "Reset Code not or not anymore available\n"
-msgstr ""
+msgstr "Tilbakestillingskode er ikke tilgjengelig\n"
 
 msgid "Your selection? "
 msgstr "Ditt valg? "
 
 msgid "[not set]"
-msgstr "[ikke satt]"
+msgstr "[ikke valgt]"
 
 msgid "male"
 msgstr "mann"
@@ -1304,10 +1240,10 @@ msgid "forced"
 msgstr "tvunget"
 
 msgid "Error: Only plain ASCII is currently allowed.\n"
-msgstr "Feil: Bare ren ASCII er foreløpig tillatt.\n"
+msgstr "Feil: Bare ren ASCII er foreløpig tillatt.\n"
 
 msgid "Error: The \"<\" character may not be used.\n"
-msgstr "Feil: Tegnet «<» kan ikke brukes.\n"
+msgstr "Feil: tegnet Â«<» kan ikke brukes.\n"
 
 msgid "Error: Double spaces are not allowed.\n"
 msgstr "Feil: Doble mellomrom er ikke tillatt.\n"
@@ -1320,178 +1256,170 @@ msgstr "Kortholders fornavn: "
 
 #, c-format
 msgid "Error: Combined name too long (limit is %d characters).\n"
-msgstr "Feil: Det kombinerte navnet er for langt (grensa går ved %d tegn).\n"
+msgstr "Feil: Det kombinerte navnet er for langt (grensa går ved %d tegn).\n"
 
 msgid "URL to retrieve public key: "
-msgstr "URL for å hente offentlig nøkkel: "
+msgstr "Adresse for henting av offentlig nøkkel: "
 
 #, c-format
 msgid "Error: URL too long (limit is %d characters).\n"
-msgstr "Feil: URL er for lang (grensa går ved %d tegn).\n"
+msgstr "Feil: Adressen er for lang (grensa er %d tegn).\n"
 
-#, fuzzy, c-format
-#| msgid "error reading `%s': %s\n"
+#, c-format
 msgid "error reading '%s': %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error writing '%s': %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under skriving av Â«%s»: %s\n"
 
 msgid "Login data (account name): "
 msgstr "Logindata (kontonavn): "
 
 #, c-format
 msgid "Error: Login data too long (limit is %d characters).\n"
-msgstr "Feil: Logindata er for langt (grensa går ved %d tegn).\n"
+msgstr "Feil: Logindata er for langt (grensa går ved %d tegn).\n"
 
 msgid "Private DO data: "
 msgstr "Privat DO-data: "
 
 #, c-format
 msgid "Error: Private DO too long (limit is %d characters).\n"
-msgstr "Feil: Privat DO for lang (grensa går ved %d tegn).\n"
+msgstr "Feil: Privat DO for lang (grensa går ved %d tegn).\n"
 
 msgid "Language preferences: "
-msgstr "Språkpreferanser:"
+msgstr "Språkoppsett: "
 
 msgid "Error: invalid length of preference string.\n"
-msgstr "Feil: ugyldig lengde på preferansestrengen.\n"
+msgstr "Feil: oppsettsstreng har ugyldig lengde.\n"
 
 msgid "Error: invalid characters in preference string.\n"
-msgstr "Feil: ugyldig tegn i preferansestrengen.\n"
+msgstr "Feil: oppsettsstreng inneholder ugyldige tegn.\n"
 
 msgid "Sex ((M)ale, (F)emale or space): "
-msgstr "Kjønn ((M)ale, (F)emale eller mellomrom): "
+msgstr "Kjønn ((M)askulint, (F)eminint eller mellomrom): "
 
 msgid "Error: invalid response.\n"
-msgstr "Feil: ugyldig respons.\n"
+msgstr "Feil: ugyldig svar.\n"
 
 msgid "CA fingerprint: "
 msgstr "CA-fingeravtrykk: "
 
 msgid "Error: invalid formatted fingerprint.\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "Feil: feilformatert fingeravtrykk.\n"
 
 #, c-format
 msgid "key operation not possible: %s\n"
-msgstr "nøkkeloperasjonen er umulig: %s\n"
+msgstr "nøkkelhåndtering er umulig. %s\n"
 
 msgid "not an OpenPGP card"
 msgstr "ikke et OpenPGP-kort"
 
 #, c-format
 msgid "error getting current key info: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under henting av info om gjeldende nøkkel. %s\n"
 
 msgid "Replace existing key? (y/N) "
-msgstr "Erstatte eksisterende nøkkel? (j/N) "
+msgstr "Erstatte eksisterende nøkkel? (j/N) "
 
 msgid ""
 "Note: There is no guarantee that the card supports the requested size.\n"
 "      If the key generation does not succeed, please check the\n"
 "      documentation of your card to see what sizes are allowed.\n"
 msgstr ""
+"MERK: Det er ingen garanti for at kortet støtter forespurt størrelse.\n"
+"      Se dokumentasjon for kortet du bruker og finn ut hvilke størrelser \n"
+"      det tillater hvis nøkkelgenerering mislykkes.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "What keysize do you want for the Signature key? (%u) "
-msgstr "Hvilken nøkkelstørrelse vil du ha? (%u) "
+msgstr "Hvor stor skal signaturnøkkelen være? (%u) "
 
-#, fuzzy, c-format
+#, c-format
 msgid "What keysize do you want for the Encryption key? (%u) "
-msgstr "Hvilken nøkkelstørrelse vil du ha? (%u) "
+msgstr "Hvor stor skal krypteringsnøkkelen være? (%u) "
 
-#, fuzzy, c-format
+#, c-format
 msgid "What keysize do you want for the Authentication key? (%u) "
-msgstr "Hvilken nøkkelstørrelse vil du ha? (%u) "
+msgstr "Hvor stor skal autentiseringsnøkkelen være? (%u) "
 
 #, c-format
 msgid "rounded up to %u bits\n"
-msgstr "rundet opp til %u bits\n"
+msgstr "rundet opp til %u bit\n"
 
 #, c-format
 msgid "%s keysizes must be in the range %u-%u\n"
-msgstr ""
+msgstr "%s nøkkelstørrelser må ligge i rekkevidden %u-%u\n"
 
 #, c-format
 msgid "The card will now be re-configured to generate a key of %u bits\n"
-msgstr ""
+msgstr "Kortet blir nå satt opp på nytt for å lage nøkkel på %u bit\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error changing size of key %d to %u bits: %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under endring av størrelse på nøkkel %d til %u bit. %s\n"
 
 msgid "Make off-card backup of encryption key? (Y/n) "
-msgstr "Lage sikkerhetskopi av krypteringsnøkler utenfor kortet? (J/n) "
+msgstr "Lage sikkerhetskopi av krypteringsnøkler utenfor kortet? (J/n) "
 
-#, fuzzy
 msgid "Note: keys are already stored on the card!\n"
-msgstr "hemmelig nøkkel er allerede lagret på et kort\n"
+msgstr "MERK: det ligger allerede nøkler på kortet.\n"
 
 msgid "Replace existing keys? (y/N) "
-msgstr "Erstatte eksisterende nøkler? (j/N) "
+msgstr "Erstatte eksisterende nøkler? (j/N) "
 
-#, fuzzy, c-format
-#| msgid ""
-#| "Please note that the factory settings of the PINs are\n"
-#| "   PIN = `%s'     Admin PIN = `%s'\n"
-#| "You should change them using the command --change-pin\n"
+#, c-format
 msgid ""
 "Please note that the factory settings of the PINs are\n"
 "   PIN = '%s'     Admin PIN = '%s'\n"
 "You should change them using the command --change-pin\n"
 msgstr ""
-"Vær obs på at fabrikkinnstilingene for PIN-kodene er\n"
-"   PIN = «%s»     Admin PIN = «%s»\n"
-"Du bør endre dem med kommandoen --change-pin\n"
+"PIN-koder fra fabrikk:\n"
+"   PIN = Â«%s»     Admin-PIN = Â«%s»\n"
+"Du bør endre disse med kommandoen «--change-pin»\n"
 
 msgid "Please select the type of key to generate:\n"
-msgstr "Vennligst velg hvilken type nøkkel du vil generere:\n"
+msgstr "Velg hvilken type nøkkel du vil lage:\n"
 
 msgid "   (1) Signature key\n"
-msgstr "   (1) Signaturnøkkel\n"
+msgstr "   (1) Signaturnøkkel\n"
 
 msgid "   (2) Encryption key\n"
-msgstr "   (2) Krypteringsnøkkel\n"
+msgstr "   (2) Krypteringsnøkkel\n"
 
 msgid "   (3) Authentication key\n"
-msgstr "   (3) Autentiseringsnøkkel\n"
+msgstr "   (3) Autentiseringsnøkkel\n"
 
 msgid "Invalid selection.\n"
 msgstr "Ugyldig valg.\n"
 
 msgid "Please select where to store the key:\n"
-msgstr "Vennligst velg hvor nøkkelen skal lagres:\n"
+msgstr "velg hvor nøkkelen skal lagres:\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "KEYTOCARD failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "KEYTOCARD mislyktes: %s\n"
 
-#, fuzzy
-#| msgid "This command is not allowed while in %s mode.\n"
 msgid "This command is not supported by this card\n"
-msgstr "Denne kommandoen er ikke tillatt i %s-modus.\n"
+msgstr "Denne kommandoen støttes ikke av dette kortet\n"
 
-#, fuzzy
 msgid "Note: This command destroys all keys stored on the card!\n"
-msgstr "hemmelig nøkkel er allerede lagret på et kort\n"
+msgstr "Merk: denne kommandoen ødelegger alle nøkler på kortet.\n"
 
-#, fuzzy
-#| msgid "Sign it? (y/N) "
 msgid "Continue? (y/N) "
-msgstr "Signere den? (j/N) "
+msgstr "Vil du fortsette? (j/N) "
 
 msgid "Really do a factory reset? (enter \"yes\") "
-msgstr ""
+msgstr "Er du sikker på at du vil gjenopprette fabrikkoppsett? (skriv «ja») "
 
 msgid "quit this menu"
-msgstr "avslutte denne menyen"
+msgstr "gå ut av denne menyen"
 
 msgid "show admin commands"
-msgstr "vise admin-kommandoer"
+msgstr "vis admin-kommandoer"
 
 msgid "show this help"
-msgstr "vise denne hjelpen"
+msgstr "vis denne hjelpeteksten"
 
 msgid "list all available data"
 msgstr "vis alle tilgjengelige data"
@@ -1500,43 +1428,43 @@ msgid "change card holder's name"
 msgstr "endre kortholders navn"
 
 msgid "change URL to retrieve key"
-msgstr "endre URL for å hente nøkkel"
+msgstr "endre adresse for å hente nøkkel"
 
 msgid "fetch the key specified in the card URL"
-msgstr "hente nøkkelen angitt i URL som er lagret i kortet"
+msgstr "hent nøkkel som ligger i kortets adresse"
 
 msgid "change the login name"
-msgstr "endre loginnavnet"
+msgstr "endre brukernavn"
 
 msgid "change the language preferences"
-msgstr "endre språkpreferansene"
+msgstr "endre språkoppsett"
 
 msgid "change card holder's sex"
-msgstr "endre kortholders kjønn"
+msgstr "endre kortholders kjønn"
 
 msgid "change a CA fingerprint"
-msgstr "vise et CA-fingeravtrykk"
+msgstr "endre CA-fingeravtrykk"
 
 msgid "toggle the signature force PIN flag"
-msgstr "veksle tving-signatur-PIN-flagget"
+msgstr "slå av på tvungen bruk av signatur-PIN"
 
 msgid "generate new keys"
-msgstr "generere nye nøkler"
+msgstr "lag nye nøkler"
 
 msgid "menu to change or unblock the PIN"
-msgstr "meny for å endre eller fjerne blokkering av PIN"
+msgstr "meny for å endre eller fjerne blokkering av PIN"
 
 msgid "verify the PIN and list all data"
 msgstr "bekrefte PIN og vise alle data"
 
 msgid "unblock the PIN using a Reset Code"
-msgstr ""
+msgstr "fjern PIN-blokkering med en tilbakestillingskode"
 
 msgid "destroy all keys and data"
-msgstr ""
+msgstr "ødelegg alle nøkler og data"
 
 msgid "gpg/card> "
-msgstr ""
+msgstr "gpg/kort> "
 
 msgid "Admin-only command\n"
 msgstr "Admin-reservert kommando\n"
@@ -1548,122 +1476,113 @@ msgid "Admin commands are not allowed\n"
 msgstr "Admin-kommandoer er ikke tillatt\n"
 
 msgid "Invalid command  (try \"help\")\n"
-msgstr "Ugyldig kommando  (prøv «help»)\n"
+msgstr "Ugyldig kommando  (prøv Â«help»)\n"
 
 msgid "--output doesn't work for this command\n"
-msgstr "--output virker ikke for denne kommandoen\n"
+msgstr "«--output» virker ikke med denne kommandoen\n"
 
-#, fuzzy, c-format
-#| msgid "can't open `%s'\n"
+#, c-format
 msgid "can't open '%s'\n"
-msgstr "kan ikke åpne «%s»\n"
+msgstr "klarte ikke Ã¥ Ã¥pne Â«%s»\n"
 
 #, c-format
 msgid "key \"%s\" not found: %s\n"
-msgstr "nøkkelen «%s» ble ikke funnet: %s\n"
+msgstr "fant ikke nøkkelen «%s». %s\n"
 
 #, c-format
 msgid "error reading keyblock: %s\n"
-msgstr "feil ved lesing av nøkkelblokk: %s\n"
+msgstr "feil under lesing av nøkkelblokk. %s\n"
 
-#, fuzzy, c-format
-#| msgid "key \"%s\" not found: %s\n"
+#, c-format
 msgid "key \"%s\" not found\n"
-msgstr "nøkkelen «%s» ble ikke funnet: %s\n"
+msgstr "fant ikke nøkkelen «%s»\n"
 
 msgid "(unless you specify the key by fingerprint)\n"
-msgstr "(med mindre du angir nøkkelen ved hjelp av fingeravtrykk)\n"
+msgstr "(med mindre du oppgir nøkkel ved hjelp av fingeravtrykk)\n"
 
 msgid "can't do this in batch mode without \"--yes\"\n"
-msgstr "kan ikke gjøre dette i batchmode uten «--yes»\n"
+msgstr "du må bruke «--yes» for å gjøre dette i buntmodus\n"
 
 msgid "Delete this key from the keyring? (y/N) "
-msgstr "Slette denne nøkkelen fra nøkkelknippet? (j/N)"
+msgstr "Vil du slette denne nøkkelen fra nøkkelknippet? (j/N) "
 
 msgid "This is a secret key! - really delete? (y/N) "
-msgstr "Dette er en hemmelig nøkkel! - virkelig slette den? (j/N)"
+msgstr ""
+"Dette er en hemmelig nøkkel. Er du sikker på at du vil slette den? (j/N) "
 
-#, fuzzy, c-format
+#, c-format
 msgid "deleting secret %s failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "sletting av hemmelig nøkkel %s mislyktes: %s\n"
 
-#, fuzzy
-#| msgid "bad key"
 msgid "key"
-msgstr "ugyldig nøkkel"
+msgstr "kkel"
 
-#, fuzzy
-#| msgid "Pubkey: "
 msgid "subkey"
-msgstr "Offentlig nøkkel: "
+msgstr "undernøkkel"
 
 #, c-format
 msgid "deleting keyblock failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "sletting av nøkkelblokk mislyktes: %s\n"
 
 msgid "ownertrust information cleared\n"
-msgstr "nullstilt informasjon om eiertillit\n"
+msgstr "informasjon om eiertillit er fjernet\n"
 
 #, c-format
 msgid "there is a secret key for public key \"%s\"!\n"
-msgstr "det finnes en hemmelig nøkkel for offentlig nøkkel «%s»!\n"
+msgstr "det finnes en hemmelig nøkkel for offentlig nøkkel «%s».\n"
 
 msgid "use option \"--delete-secret-keys\" to delete it first.\n"
-msgstr "bruk valget «--delete-secret-keys» for å slette den først.\n"
+msgstr "bruk valget «--delete-secret-keys» for å slette den først.\n"
 
 #, c-format
 msgid "error creating passphrase: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under opprettelse av passordfrase. %s\n"
 
 msgid "can't use a symmetric ESK packet due to the S2K mode\n"
-msgstr "kan ikke bruke en symmetrisk ESK-pakke på grunn av S2K-modusen\n"
+msgstr "klarte ikke å bruke symmetrisk ESK-pakke på grunn av S2K-modus\n"
 
 #, c-format
 msgid "using cipher %s\n"
-msgstr "bruker cipher %s\n"
+msgstr "bruker krypteringsmetode %s\n"
 
-#, fuzzy, c-format
-#| msgid "`%s' already compressed\n"
+#, c-format
 msgid "'%s' already compressed\n"
-msgstr "«%s» er allerede komprimert\n"
+msgstr "«%s» er allerede komprimert\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: `%s' is an empty file\n"
+#, c-format
 msgid "WARNING: '%s' is an empty file\n"
-msgstr "ADVARSEL: «%s» er en tom fil\n"
+msgstr "ADVARSEL: Â«%s» er en tom fil\n"
 
-#, fuzzy, c-format
-#| msgid "reading from `%s'\n"
+#, c-format
 msgid "reading from '%s'\n"
-msgstr "leser fra «%s»\n"
+msgstr "leser fra Â«%s»\n"
 
 #, c-format
 msgid ""
 "WARNING: forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr ""
-"ADVARSEL: påtvinging av symmetrisk cipher %s (%d) bryter med mottakerens "
-"preferanser\n"
+"ADVARSEL: tvungen bruk av symmetrisk krypt.metode %s (%d) bryter med "
+"mottakers oppsett\n"
 
 #, c-format
 msgid ""
 "WARNING: forcing compression algorithm %s (%d) violates recipient "
 "preferences\n"
 msgstr ""
-"ADVARSEL: tvang av kompresjonsalgoritme %s (%d) bryter med mottakerens "
-"preferanser\n"
+"ADVARSEL: tvungen bruk av komprimeringsalgoritme %s (%d) bryter med "
+"mottakers oppsett\n"
 
 #, c-format
 msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
-msgstr ""
-"påtvinging av symmetrisk cipher %s (%d) bryter med mottakerens preferanser\n"
+msgstr "tvungen bruk av krypt.metode %s (%d) bryter med mottakers oppsett\n"
 
 #, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
-msgstr "%s/%s kryptert for: \"%s\"\n"
+msgstr "%s/%s kryptert for: «%s»\n"
 
 #, c-format
 msgid "you may not use %s while in %s mode\n"
-msgstr "du kan ikke bruke %s i %s modus\n"
+msgstr "du kan ikke bruke «%s» i «%s»-modus\n"
 
 #, c-format
 msgid "%s encrypted data\n"
@@ -1676,319 +1595,301 @@ msgstr "kryptert med en ukjent algoritme %d\n"
 msgid ""
 "WARNING: message was encrypted with a weak key in the symmetric cipher.\n"
 msgstr ""
-"ADVARSEL: meldingen er kryptert med en svak nøkkel for den symmetriske "
-"cipher.\n"
+"ADVARSEL: meldinga ble kryptert med svak nøkkel for symmetrisk "
+"krypteringsmetode.\n"
 
 msgid "problem handling encrypted packet\n"
-msgstr "problem ved håndtering av kryptert pakke\n"
+msgstr "problem ved håndtering av kryptert pakke\n"
 
 msgid "no remote program execution supported\n"
-msgstr "fjernutføring av programmer er ikke støttet\n"
+msgstr "fjernutføring av programmer er ikke støttet\n"
 
 msgid ""
 "external program calls are disabled due to unsafe options file permissions\n"
 msgstr ""
-"eksterne programkall er utkoblet på grunn av utrygge rettigheter på "
-"konfigurasjonsfila\n"
+"eksterne programkall er slått av på grunn av utrygge tillatelser til "
+"oppsettsfil\n"
 
 msgid "this platform requires temporary files when calling external programs\n"
 msgstr ""
-"denne plattformen krever midlertidige filer ved kall på eksterne programmer\n"
+"denne plattformen krever midlertidige filer ved kall på eksterne programmer\n"
 
-#, fuzzy, c-format
-#| msgid "unable to execute program `%s': %s\n"
+#, c-format
 msgid "unable to execute program '%s': %s\n"
-msgstr "kunne ikke utføre program «%s»: %s\n"
+msgstr "klarte ikke Ã¥ kjøre Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "unable to execute shell `%s': %s\n"
+#, c-format
 msgid "unable to execute shell '%s': %s\n"
-msgstr "kunne ikke utføre skallet «%s»: %s\n"
+msgstr "klarte ikke Ã¥ kjøre skallet Â«%s»: %s\n"
 
 #, c-format
 msgid "system error while calling external program: %s\n"
-msgstr "systemfeil under kall på eksternt program: %s\n"
+msgstr "systemfeil under kall på eksternt program: %s\n"
 
 msgid "unnatural exit of external program\n"
 msgstr "unaturlig avslutning av eksternt program\n"
 
 msgid "unable to execute external program\n"
-msgstr "klarte ikke å kjøre eksternt program\n"
+msgstr "klarte ikke å kjøre eksternt program\n"
 
 #, c-format
 msgid "unable to read external program response: %s\n"
-msgstr "klarte ikke å lese reponsen fra eksternt program: %s\n"
+msgstr "klarte ikke å lese reponsen fra eksternt program: %s\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unable to remove tempfile (%s) `%s': %s\n"
+#, c-format
 msgid "WARNING: unable to remove tempfile (%s) '%s': %s\n"
-msgstr "ADVARSEL: klarte ikke å fjerne midlertidig fil (%s) «%s»: %s\n"
+msgstr "ADVARSEL: klarte ikke Ã¥ fjerne midlertidig fil (%s) Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unable to remove temp directory `%s': %s\n"
+#, c-format
 msgid "WARNING: unable to remove temp directory '%s': %s\n"
-msgstr "ADVARSEL: klarte ikke å fjerne midlertidig katalog «%s»: %s\n"
+msgstr "ADVARSEL: klarte ikke Ã¥ fjerne midlertidig mappe Â«%s»: %s\n"
 
 msgid "export signatures that are marked as local-only"
 msgstr "eksportere signaturer som er markert som bare-lokale"
 
 msgid "export attribute user IDs (generally photo IDs)"
-msgstr ""
+msgstr "eksporter bruker-id-er (generelt foto-id-er)"
 
 msgid "export revocation keys marked as \"sensitive\""
-msgstr ""
+msgstr "eksporter opphevelsesnøkler markert som «sensitive»"
 
 msgid "remove unusable parts from key during export"
-msgstr ""
+msgstr "fjern ubrukelige deler fra nøkkelen under eksportering"
 
 msgid "remove as much as possible from key during export"
-msgstr ""
+msgstr "fjern så mye som mulig fra nøkkelen under eksportering"
 
-#, fuzzy
-#| msgid "%s: skipped: %s\n"
 msgid " - skipped"
-msgstr "%s: hoppet over: %s\n"
-
-msgid "exporting secret keys not allowed\n"
-msgstr "eksportering av hemmelige nøkler er ikke tillatt\n"
+msgstr ". Hoppet over"
 
 #, c-format
-msgid "key %s: PGP 2.x style key - skipped\n"
-msgstr "nøkkel %s: PGP 2.x-aktig nøkkel - hoppet over\n"
+msgid "writing to '%s'\n"
+msgstr "skriver til «%s»\n"
 
 #, c-format
 msgid "key %s: key material on-card - skipped\n"
-msgstr "nøkkel %s: nøkkelmateriell på kort - hoppet over\n"
+msgstr "nøkkel %s: nøkkelmateriell på kort - hoppet over\n"
+
+msgid "exporting secret keys not allowed\n"
+msgstr "eksportering av hemmelige nøkler er ikke tillatt\n"
+
+#, c-format
+msgid "key %s: PGP 2.x style key - skipped\n"
+msgstr "nøkkel %s: PGP 2.x-aktig nøkkel - hoppet over\n"
 
 msgid "WARNING: nothing exported\n"
 msgstr "ADVARSEL: ingenting eksportert\n"
 
-#, fuzzy, c-format
-#| msgid "error reading `%s': %s\n"
+#, c-format
 msgid "error creating '%s': %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under oppretting av Â«%s»: %s\n"
 
 msgid "[User ID not found]"
-msgstr "[Brukerid ikke funnet]"
+msgstr "[Fant ikke bruker-ID]"
 
-#, fuzzy, c-format
+#, c-format
 msgid "(check argument of option '%s')\n"
-msgstr "ugyldige listevalg\n"
+msgstr "(kontroller argument for valget «%s»)\n"
 
 #, c-format
 msgid "Warning: '%s' should be a long key ID or a fingerprint\n"
-msgstr ""
+msgstr "Advarsel: «%s» må være en lang nøkkel-ID eller et fingeravtrykk\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error looking up: %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under oppslag av %s\n"
 
-#, fuzzy, c-format
-#| msgid "error creating keyring `%s': %s\n"
+#, c-format
 msgid "Warning: %s appears in the keyring %d times\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "Advarsel: %s står oppført på nøkkelknippet %d ganger\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "automatically retrieved '%s' via %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "hentet «%s» via %s automatisk\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error retrieving '%s' via %s: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under henting av «%s» via %s: %s\n"
 
-#, fuzzy
 msgid "No fingerprint"
-msgstr "CA-fingeravtrykk: "
+msgstr "Ingen fingeravtrykk"
 
 #, c-format
 msgid "secret key \"%s\" not found: %s\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "fant ikke hemmelig nøkkel «%s». %s\n"
 
-#, fuzzy, c-format
-#| msgid "unusable secret key"
+#, c-format
 msgid "Warning: not using '%s' as default key: %s\n"
-msgstr "ubrukelig hemmelig nøkkel"
+msgstr "Advarsel: bruker ikke «%s» som forvalgt nøkkel: %s\n"
 
-#, fuzzy, c-format
-#| msgid "unusable secret key"
+#, c-format
 msgid "using \"%s\" as default secret key for signing\n"
-msgstr "ubrukelig hemmelig nøkkel"
+msgstr "bruker «%s» som forvalgt hemmelig signeringsnøkkel\n"
 
 #, c-format
 msgid "all values passed to '%s' ignored\n"
-msgstr ""
+msgstr "alle verdier som sendes til «%s» blir ignorert\n"
 
 #, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
-msgstr "Ugyldig nøkkel %s gjort gyldig av --allow-non-selfsigned-uid\n"
+msgstr "Ugyldig nøkkel %s gjort gyldig av --allow-non-selfsigned-uid\n"
 
 #, c-format
 msgid "using subkey %s instead of primary key %s\n"
-msgstr "bruker undernøkkel %s i stedet for primærnøkkel %s\n"
+msgstr "bruker undernøkkel %s i stedet for primærnøkkel %s\n"
 
-#, fuzzy
 msgid "make a signature"
-msgstr "|[fil]|lage en signatur"
+msgstr "lag signatur"
 
-#, fuzzy
 msgid "make a clear text signature"
-msgstr "|[fil]|lage en klartekstsignatur"
+msgstr "lag klartekst-signatur"
 
 msgid "make a detached signature"
-msgstr "lage en adskilt signatur"
+msgstr "lag adskilt signatur"
 
 msgid "encrypt data"
-msgstr "kryptere data"
+msgstr "krypter data"
 
 msgid "encryption only with symmetric cipher"
-msgstr "kryptering med bare symmetrisk cipher"
+msgstr "krypter data (symmetrisk)"
 
 msgid "decrypt data (default)"
-msgstr "dekryptere data (standard)"
+msgstr "dekrypter data (forvalgt)"
 
 msgid "verify a signature"
-msgstr "bekrefte en signatur"
+msgstr "bekreft signatur"
 
 msgid "list keys"
-msgstr "liste nøkler"
+msgstr "vis nøkler"
 
 msgid "list keys and signatures"
-msgstr "liste nøkler og signaturer"
+msgstr "vis nøkler og signaturer"
 
 msgid "list and check key signatures"
-msgstr "vise og sjekke nøkkelsignaturer"
+msgstr "vis og kontroller nøkkelsignaturer"
 
 msgid "list keys and fingerprints"
-msgstr "liste nøkler og fingeravtrykk"
+msgstr "vis nøkler og fingeravtrykk"
 
 msgid "list secret keys"
-msgstr "liste hemmelige nøkler"
+msgstr "vis hemmelige nøkler"
 
 msgid "generate a new key pair"
-msgstr "generere et nytt nøkkelpar"
+msgstr "lag nytt nøkkelpar"
 
-#, fuzzy
-#| msgid "generate a new key pair"
 msgid "quickly generate a new key pair"
-msgstr "generere et nytt nøkkelpar"
+msgstr "lag nytt nøkkelpar raskt"
 
-#, fuzzy
-#| msgid "generate a new key pair"
 msgid "quickly add a new user-id"
-msgstr "generere et nytt nøkkelpar"
+msgstr "legg til en ny bruker-ID raskt"
+
+#, fuzzy
+#| msgid "quickly add a new user-id"
+msgid "quickly revoke a user-id"
+msgstr "legg til en ny bruker-ID raskt"
 
 msgid "full featured key pair generation"
-msgstr ""
+msgstr "fullverdig generering av nøkkelpar"
 
 msgid "generate a revocation certificate"
-msgstr "generere et opphevingssertifikat"
+msgstr "lag opphevelsessertifikat"
 
 msgid "remove keys from the public keyring"
-msgstr "fjerne nøkler fra det offentlige nøkkelknippet"
+msgstr "fjern nøkler fra offentlig nøkkelknippe"
 
 msgid "remove keys from the secret keyring"
-msgstr "fjerne nøkler fra det hemmelige nøkkelknippet"
+msgstr "fjern nøkler fra hemmelig nøkkelknippe"
 
-#, fuzzy
-#| msgid "sign a key"
 msgid "quickly sign a key"
-msgstr "signere en nøkkel"
+msgstr "hurtigsigner nøkkel"
 
-#, fuzzy
-#| msgid "sign a key locally"
 msgid "quickly sign a key locally"
-msgstr "signere en nøkkel lokalt"
+msgstr "hurtigsigner nøkkel lokalt"
 
 msgid "sign a key"
-msgstr "signere en nøkkel"
+msgstr "signer nøkkel"
 
 msgid "sign a key locally"
-msgstr "signere en nøkkel lokalt"
+msgstr "signer nøkkel lokalt"
 
 msgid "sign or edit a key"
-msgstr "signere eller redigere en nøkkel"
+msgstr "signer eller rediger nøkkel"
 
-#, fuzzy
 msgid "change a passphrase"
-msgstr "endre passfrasen"
+msgstr "endre passordfrase"
 
 msgid "export keys"
-msgstr "eksportere nøkler"
+msgstr "eksporter nøkler"
 
 msgid "export keys to a keyserver"
-msgstr "eksportere nøkler til en nøkkelserver"
+msgstr "eksporter nøkler til nøkkeltjener"
 
 msgid "import keys from a keyserver"
-msgstr "importere nøkler fra en nøkkelserver"
+msgstr "importer nøkler fra nøkkeltjener"
 
 msgid "search for keys on a keyserver"
-msgstr "søke etter nøkler på en nøkkelserver"
+msgstr "søk etter nøkler på nøkkeltjener"
 
 msgid "update all keys from a keyserver"
-msgstr "oppdatere alle nøklene fra en nøkkelserver"
+msgstr "oppdater alle nøkler fra nøkkeltjener"
 
 msgid "import/merge keys"
-msgstr "importere/flette nøkler"
+msgstr "importer/slå sammen nøkler"
 
 msgid "print the card status"
-msgstr "vis kortets status"
+msgstr "vis kortstatus"
 
 msgid "change data on a card"
-msgstr "endre data på et kort"
+msgstr "endre data på kort"
 
 msgid "change a card's PIN"
-msgstr "endre PIN på et kort"
+msgstr "endre PIN på kort"
 
 msgid "update the trust database"
-msgstr "oppdatere tillitsdatabasen"
+msgstr "oppdater tillitsdatabase"
 
-#, fuzzy
 msgid "print message digests"
-msgstr "|algo [filer]|skrive meldingsdigester"
+msgstr "skriv ut kontrollsum av melding"
 
 msgid "run in server mode"
-msgstr ""
+msgstr "kjør i tjenermodus"
 
 msgid "|VALUE|set the TOFU policy for a key"
-msgstr ""
+msgstr "|VERDI|endre TOFU-regler for nøkkel"
 
 msgid "create ascii armored output"
-msgstr "lage ASCII-beskyttet output"
+msgstr "lag ASCII-beskyttet utdata"
 
-#, fuzzy
 msgid "|USER-ID|encrypt for USER-ID"
-msgstr "|NAVN|kryptere for NAVN"
+msgstr "|BRUKER-ID|krypter for valgt BRUKER-ID"
 
-#, fuzzy
 msgid "|USER-ID|use USER-ID to sign or decrypt"
-msgstr "bruke denne brukeriden for signering eller dekryptering"
+msgstr "|BRUKER-ID|bruk valgt BRUKER-ID til å signere eller dekryptere"
 
-#, fuzzy
 msgid "|N|set compress level to N (0 disables)"
-msgstr "|N|sette kompresjonsnivå til N (0 slår av kompresjon)"
+msgstr "|N|endre komprimeringsnivå til N (0 for å slå av)"
 
 msgid "use canonical text mode"
 msgstr "bruk kanonisk tekstmodus"
 
-#, fuzzy
 msgid "|FILE|write output to FILE"
-msgstr "leser valg fra «%s»\n"
+msgstr "|FILE|skriv utdata til valgt FIL"
 
 msgid "do not make any changes"
-msgstr "ikke gjør noen endringer"
+msgstr "ikke utfør valgte endringer"
 
 msgid "prompt before overwriting"
-msgstr "spør før overskriving"
+msgstr "spør før overskriving"
 
 msgid "use strict OpenPGP behavior"
-msgstr "bruk streng OpenPGP-oppførsel"
+msgstr "bruk streng OpenPGP-oppførsel"
 
 msgid ""
 "@\n"
 "(See the man page for a complete listing of all commands and options)\n"
 msgstr ""
 "@\n"
-"(Se mansiden for en komplett liste over alle kommandoene og valgene)\n"
+"(Se bruksanvisning for en fullstendig liste over alle kommandoer og valg)\n"
 
 msgid ""
 "@\n"
@@ -2003,248 +1904,210 @@ msgstr ""
 "@\n"
 "Eksempler:\n"
 "\n"
-" -se -r Bob [fil]           signere og kryptere for brukeren Bob\n"
-" --clearsign [fil]          lage en klartekstsignatur\n"
-" --detach-sign [fil]        lage en adskilt signatur\n"
-" --list-keys [navn]         vise nøkler\n"
-" --fingerprint [navn]       vise fingeravtrykk\n"
+" -se -r Bob [fil]           signer og krypter for brukeren Bob\n"
+" --clearsign [fil]          lag klartekst-signatur\n"
+" --detach-sign [fil]        lag adskilt signatur\n"
+" --list-keys [navn]         vis nøkler\n"
+" --fingerprint [navn]       vis fingeravtrykk\n"
 
-#, fuzzy
-#| msgid "Usage: gpg [options] [files] (-h for help)"
 msgid "Usage: @GPG@ [options] [files] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: @GPG@ [valg] [filer] (-h for hjelp)"
 
-#, fuzzy
-#| msgid ""
-#| "Syntax: gpg [options] [files]\n"
-#| "sign, check, encrypt or decrypt\n"
-#| "default operation depends on the input data\n"
 msgid ""
 "Syntax: @GPG@ [options] [files]\n"
 "Sign, check, encrypt or decrypt\n"
 "Default operation depends on the input data\n"
 msgstr ""
-"Bruksmåte: gpg [valg] [filer]\n"
-"signere, sjekke, kryptere eller dekryptere\n"
-"standard operasjon avhenger av inputdata\n"
+"Syntaks: gpg [valg] [filer]\n"
+"Signer, kontroller, krypter eller dekrypter.\n"
+"Forvalgt handling avhenger av inndata.\n"
 
 msgid ""
 "\n"
 "Supported algorithms:\n"
 msgstr ""
 "\n"
-"Støttede algoritmer:\n"
+"Støttede algoritmer:\n"
 
 msgid "Pubkey: "
-msgstr "Offentlig nøkkel: "
+msgstr "Off. nøkkel: "
 
 msgid "Cipher: "
-msgstr "Cipher: "
+msgstr "Kryptering: "
 
 msgid "Hash: "
 msgstr "Hash: "
 
 msgid "Compression: "
-msgstr "Kompresjon: "
+msgstr "Komprimering: "
 
-#, fuzzy, c-format
+#, c-format
 msgid "usage: %s [options] %s\n"
-msgstr "bruksmåte: gpg [valg] "
+msgstr "bruk: %s [valg] %s\n"
 
 msgid "conflicting commands\n"
 msgstr "motstridende kommandoer\n"
 
-#, fuzzy, c-format
-#| msgid "no = sign found in group definition `%s'\n"
+#, c-format
 msgid "no = sign found in group definition '%s'\n"
-msgstr "fant ingen «=»-tegn i gruppedefinisjonen «%s»\n"
+msgstr "fant ingen Â«=»-tegn i gruppedefinisjon Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe ownership on homedir `%s'\n"
+#, c-format
 msgid "WARNING: unsafe ownership on homedir '%s'\n"
-msgstr "ADVARSEL: utrygt eierskap på hjemmekatalogen «%s»\n"
+msgstr "ADVARSEL: utrygt eierskap til hjemmemappe Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe ownership on configuration file `%s'\n"
+#, c-format
 msgid "WARNING: unsafe ownership on configuration file '%s'\n"
-msgstr "ADVARSEL: utrygt eierskap på konfigurasjonsfilen «%s»\n"
+msgstr "ADVARSEL: utrygt eierskap til oppsettsfil Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe ownership on extension `%s'\n"
+#, c-format
 msgid "WARNING: unsafe ownership on extension '%s'\n"
-msgstr "ADVARSEL: utrygt eierskap på utvidelsen «%s»\n"
+msgstr "ADVARSEL: utrygt eierskap til utvidelse Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe permissions on homedir `%s'\n"
+#, c-format
 msgid "WARNING: unsafe permissions on homedir '%s'\n"
-msgstr "ADVARSEL: utrygge rettigheter på hjemmekatalogen «%s»\n"
+msgstr "ADVARSEL: utrygge tillatelser til hjemmemappe Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe permissions on configuration file `%s'\n"
+#, c-format
 msgid "WARNING: unsafe permissions on configuration file '%s'\n"
-msgstr "ADVARSEL: utrygge rettigheter på konfigurasjonsfilen «%s»\n"
+msgstr "ADVARSEL: utrygge tillatelser til oppsettsfil Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe permissions on extension `%s'\n"
+#, c-format
 msgid "WARNING: unsafe permissions on extension '%s'\n"
-msgstr "ADVARSEL: utrygge rettigheter på utvidelsen «%s»\n"
+msgstr "ADVARSEL: utrygge tillatelser til utvidelse Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe enclosing directory ownership on homedir `%s'\n"
+#, c-format
 msgid "WARNING: unsafe enclosing directory ownership on homedir '%s'\n"
-msgstr ""
-"ADVARSEL: utrygt eierskap på katalogene på nivåene over hjemmekatalogen "
-"«%s»\n"
+msgstr "ADVARSEL: utrgt eierskap til foreldermapper av hjemmemappe «%s»\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "WARNING: unsafe enclosing directory ownership on configuration file `%s'\n"
+#, c-format
 msgid ""
 "WARNING: unsafe enclosing directory ownership on configuration file '%s'\n"
-msgstr ""
-"ADVARSEL: utrygt eierskap på katalogene på nivåene over konfigurasjonsfilen "
-"«%s»\n"
+msgstr "ADVARSEL: utrgt eierskap til foreldermapper av oppsettsfil «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe enclosing directory ownership on extension `%s'\n"
+#, c-format
 msgid "WARNING: unsafe enclosing directory ownership on extension '%s'\n"
-msgstr ""
-"ADVARSEL: utrygt eierskap på katalogene på nivåene over utvidelsen «%s»\n"
+msgstr "ADVARSEL: utrgt eierskap til foreldermapper av utvidelse «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe enclosing directory permissions on homedir `%s'\n"
+#, c-format
 msgid "WARNING: unsafe enclosing directory permissions on homedir '%s'\n"
-msgstr ""
-"ADVARSEL: utrygge rettigheter på katalogene på nivåene over hjemmekatalogen "
-"«%s»\n"
+msgstr "ADVARSEL: utrygge tillatelser til foreldermapper av hjemmemappe «%s»\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "WARNING: unsafe enclosing directory permissions on configuration file `"
-#| "%s'\n"
+#, c-format
 msgid ""
 "WARNING: unsafe enclosing directory permissions on configuration file '%s'\n"
-msgstr ""
-"ADVARSEL: utrygge rettigheter på katalogene på nivåene over "
-"konfigurasjonsfilen «%s»\n"
+msgstr "ADVARSEL: utrygge tillatelser til foreldermapper av oppsettsfil «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: unsafe enclosing directory permissions on extension `%s'\n"
+#, c-format
 msgid "WARNING: unsafe enclosing directory permissions on extension '%s'\n"
-msgstr ""
-"ADVARSEL: utrygge rettigheter på katalogene på nivåene over utvidelsen «%s»\n"
+msgstr "ADVARSEL: utrygge tillatelser til foreldermapper av utvidelse «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "unknown configuration item `%s'\n"
+#, c-format
 msgid "unknown configuration item '%s'\n"
-msgstr "ukjent konfigurasjonspunkt «%s»\n"
+msgstr "oppsettselementet «%s» er ukjent\n"
 
 msgid "display photo IDs during key listings"
-msgstr ""
+msgstr "vis foto-id-er i nøkkelvisning"
 
-#, fuzzy
-#| msgid "show the keyring name in key listings"
 msgid "show key usage information during key listings"
-msgstr "vise navnet til nøkkelknippene i nøkkellister"
+msgstr "vis informasjon om nøkkelbruk i nøkkelvisning"
 
 msgid "show policy URLs during signature listings"
-msgstr ""
+msgstr "vis regeladresser i signaturvisning"
 
 msgid "show all notations during signature listings"
-msgstr ""
+msgstr "vis alle notater i signaturvisning"
 
 msgid "show IETF standard notations during signature listings"
-msgstr ""
+msgstr "vis IETF-standardnotater under signaturvisning"
 
 msgid "show user-supplied notations during signature listings"
-msgstr ""
+msgstr "vis brukervalgte notater under signaturvisning"
 
 msgid "show preferred keyserver URLs during signature listings"
-msgstr ""
+msgstr "vis foretrukne nøkkeltjener-adresser under signaturvisning"
 
 msgid "show user ID validity during key listings"
-msgstr ""
+msgstr "vis gyldighet for bruker-ID under nøkkelvisning"
 
 msgid "show revoked and expired user IDs in key listings"
-msgstr ""
+msgstr "vis opphevede og utgåtte bruker-id-er i nøkkelvisning"
 
 msgid "show revoked and expired subkeys in key listings"
-msgstr ""
+msgstr "vis opphevede og utgåtte undernøkler i nøkkelvisning"
 
 msgid "show the keyring name in key listings"
-msgstr "vise navnet til nøkkelknippene i nøkkellister"
+msgstr "vis nøkkelknippe-navn i nøkkelvisning"
 
 msgid "show expiration dates during signature listings"
-msgstr ""
+msgstr "vis utløpsdatoer i nøkkelvisning"
 
-#, fuzzy
 msgid "available TOFU policies:\n"
-msgstr "utkoble en nøkkel"
+msgstr "tilgjengelige TOFU-regler:\n"
 
-#, fuzzy, c-format
-#| msgid "unknown option `%s'\n"
+#, c-format
 msgid "unknown TOFU policy '%s'\n"
-msgstr "ukjent valg «%s»\n"
+msgstr "«%s» er et ukjent TOFU-regelverk\n"
 
 msgid "(use \"help\" to list choices)\n"
-msgstr ""
+msgstr "(bruk «help» for å vise valg)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unknown TOFU DB format '%s'\n"
-msgstr "ukjent valg «%s»\n"
+msgstr "«%s» er et ukjent TOFU DB-format\n"
 
-#, fuzzy, c-format
-#| msgid "NOTE: old default options file `%s' ignored\n"
+#, c-format
 msgid "Note: old default options file '%s' ignored\n"
-msgstr "MERK: den gamle valgfila «%s» ble ignorert\n"
+msgstr "Merk: gammel standardvalgfil Â«%s» ble ignorert\n"
 
 #, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
-msgstr ""
+msgstr "libgcrypt er for gammelt (krever %s, har %s)\n"
 
-#, fuzzy, c-format
-#| msgid "NOTE: %s is not for normal use!\n"
+#, c-format
 msgid "Note: %s is not for normal use!\n"
-msgstr "MERK: %s er ikke for vanlig bruk!\n"
+msgstr "Merk: %s er ikke ment for vanlig bruk.\n"
 
-# Tenk litt på denne du, Trond.
-#, fuzzy, c-format
-#| msgid "`%s' is not a valid signature expiration\n"
+#, c-format
 msgid "'%s' is not a valid signature expiration\n"
-msgstr "«%s» er ikke en gyldig signaturutgåelse\n"
+msgstr "«%s» er en ugyldig signatur-utløpstid\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid pinentry mode '%s'\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "PIN-inntastingsmodus «%s» er ugyldig\n"
 
-#, fuzzy, c-format
-#| msgid "`%s' is not a valid character set\n"
+#, c-format
 msgid "'%s' is not a valid character set\n"
-msgstr "«%s» er ikke et gyldig tegnsett\n"
+msgstr "«%s» er ikke et gyldig tegnsett\n"
 
 msgid "could not parse keyserver URL\n"
-msgstr "kunne ikke parse nøkkelserverens URL\n"
+msgstr "klarte ikke å tolke nøkkeltjener-adresse\n"
 
 #, c-format
 msgid "%s:%d: invalid keyserver options\n"
-msgstr "%s:%d: ugyldige valg for nøkkelserver\n"
+msgstr "%s:%d: ugyldige nøkkeltjener-valg\n"
 
 msgid "invalid keyserver options\n"
-msgstr "ugyldige valg for nøkkelserver\n"
+msgstr "ugyldige nøkkeltjener-valg\n"
 
 #, c-format
 msgid "%s:%d: invalid import options\n"
-msgstr "%s:%d: ugyldige importvalg\n"
+msgstr "%s:%d: ugyldige importeringsvalg\n"
 
 msgid "invalid import options\n"
-msgstr "ugyldige importvalg\n"
+msgstr "ugyldige importeringsvalg\n"
+
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "ugyldige listevalg\n"
 
 #, c-format
 msgid "%s:%d: invalid export options\n"
-msgstr "%s:%d: ugyldige eksportvalg\n"
+msgstr "%s:%d: ugyldige eksporteringsvalg\n"
 
 msgid "invalid export options\n"
-msgstr "ugyldige eksportvalg\n"
+msgstr "ugyldige eksporteringsvalg\n"
 
 #, c-format
 msgid "%s:%d: invalid list options\n"
@@ -2254,58 +2117,58 @@ msgid "invalid list options\n"
 msgstr "ugyldige listevalg\n"
 
 msgid "display photo IDs during signature verification"
-msgstr ""
+msgstr "vis bruker-ID under signaturbekreftelse"
 
 msgid "show policy URLs during signature verification"
-msgstr ""
+msgstr "vis adresser til retningslinjer under signaturbekreftelse"
 
 msgid "show all notations during signature verification"
-msgstr ""
+msgstr "vis alle merknader under signaturbekreftelse"
 
 msgid "show IETF standard notations during signature verification"
-msgstr ""
+msgstr "vis IETF-standardnotater under signaturbekreftelse"
 
 msgid "show user-supplied notations during signature verification"
-msgstr ""
+msgstr "vis selvvalgte merknader under signaturbekreftelse"
 
 msgid "show preferred keyserver URLs during signature verification"
-msgstr ""
+msgstr "vis adresser til foretrukne nøkkeltjenere under signaturbekreftelse"
 
 msgid "show user ID validity during signature verification"
-msgstr ""
+msgstr "vis gyldighet for bruker-ID under signaturbekreftelse"
 
 msgid "show revoked and expired user IDs in signature verification"
-msgstr ""
+msgstr "vis opphevede og utgåtte bruker-id-er under signaturbekreftelse"
 
 msgid "show only the primary user ID in signature verification"
-msgstr ""
+msgstr "bare vis primærbrukerens ID under signaturbekreftelse"
 
 msgid "validate signatures with PKA data"
-msgstr ""
+msgstr "kontroller signaturer som har PKA-data"
 
 msgid "elevate the trust of signatures with valid PKA data"
-msgstr ""
+msgstr "øk tillitsnivå for signaturer med gyldige PKA-data"
 
 #, c-format
 msgid "%s:%d: invalid verify options\n"
-msgstr "%s:%d: ugyldige valg for bekreftelse\n"
+msgstr "%s:%d: ugyldige kontrollvalg\n"
 
 msgid "invalid verify options\n"
-msgstr "ugyldige valg for bekreftelse\n"
+msgstr "ugyldige kontrollvalg\n"
 
 #, c-format
 msgid "unable to set exec-path to %s\n"
-msgstr "kunne ikke sette exec-path til %s\n"
+msgstr "klarte ikke å endre «exec»-sti til %s\n"
 
 #, c-format
 msgid "%s:%d: invalid auto-key-locate list\n"
-msgstr "%s:%d: ugyldig auto-key-locate-liste\n"
+msgstr "%s:%d: ugyldig «auto-key-locate»-liste\n"
 
 msgid "invalid auto-key-locate list\n"
-msgstr ""
+msgstr "ugyldig «auto-key-locate»-liste\n"
 
 msgid "WARNING: program may create a core file!\n"
-msgstr "ADVARSEL: programmet kan opprette en corefil!\n"
+msgstr "ADVARSEL: programmet kan lage en kjernefil.\n"
 
 #, c-format
 msgid "WARNING: %s overrides %s\n"
@@ -2313,92 +2176,86 @@ msgstr "ADVARSEL: %s overstyrere %s\n"
 
 #, c-format
 msgid "%s not allowed with %s!\n"
-msgstr "%s er ikke tillatt sammen med %s!\n"
+msgstr "du kan ikke bruke %s med %s.\n"
 
 #, c-format
 msgid "%s makes no sense with %s!\n"
-msgstr "%s er ikke fornuftig med %s!\n"
+msgstr "%s gir ikke mening med %s.\n"
 
 msgid "WARNING: running with faked system time: "
-msgstr ""
+msgstr "ADVARSEL: kjører med falsk systemtid: "
 
 #, c-format
 msgid "will not run with insecure memory due to %s\n"
-msgstr ""
+msgstr "lar være å kjøre med usikret minne pga. %s\n"
 
 msgid "selected cipher algorithm is invalid\n"
 msgstr "valgt krypteringsalgoritme er ugyldig\n"
 
 msgid "selected digest algorithm is invalid\n"
-msgstr "valg digestalgoritme er ugyldig\n"
+msgstr "valg kontrollsum-algoritme er ugyldig\n"
 
 msgid "selected compression algorithm is invalid\n"
-msgstr "valgt kompresjonsalgoritme er ugyldig\n"
+msgstr "valgt komprimeringsalgoritme er ugyldig\n"
 
 msgid "selected certification digest algorithm is invalid\n"
-msgstr "valgt sertifikasjondigestalgoritme er ugyldig\n"
+msgstr "valgt kontrollsum-algoritme for sertifisering er ugyldig\n"
 
 msgid "completes-needed must be greater than 0\n"
-msgstr "completes-needed må være større enn 0\n"
+msgstr "«completes-needed» må være større enn 0\n"
 
 msgid "marginals-needed must be greater than 1\n"
-msgstr "marginals-neede må være større enn 1\n"
+msgstr "«marginals-needed» må være større enn 1\n"
 
 msgid "max-cert-depth must be in the range from 1 to 255\n"
-msgstr "max-cert-depth må være i intervallet fra 1 til 255\n"
+msgstr "«max-cert-depth» må være mellom 1 og 255\n"
 
 msgid "invalid default-cert-level; must be 0, 1, 2, or 3\n"
-msgstr "ugyldig default-cert-level; må være 0, 1, 2 eller 3\n"
+msgstr "ugyldig «default-cert-level» (må være 0, 1, 2 eller 3)\n"
 
 msgid "invalid min-cert-level; must be 1, 2, or 3\n"
-msgstr "ugyldig min-cert-level; må være 0, 1, 2 eller 3\n"
+msgstr "ugyldig «min-cert-level» (må være 0, 1, 2 eller 3)\n"
 
-#, fuzzy
-#| msgid "NOTE: simple S2K mode (0) is strongly discouraged\n"
 msgid "Note: simple S2K mode (0) is strongly discouraged\n"
-msgstr "MERK: enkel S2K-modus (0) er sterkt frarådet\n"
+msgstr "Merk: enkel S2K-modus (0) er sterkt frarådet\n"
 
 msgid "invalid S2K mode; must be 0, 1 or 3\n"
-msgstr "ugyldig S2K-modus; må være 0, 1 eller 3\n"
+msgstr "ugyldig S2K-modus (må være 0, 1 eller 3)\n"
 
 msgid "invalid default preferences\n"
-msgstr "ugyldig standard preferanser\n"
+msgstr "ugyldig standardoppsett\n"
 
 msgid "invalid personal cipher preferences\n"
-msgstr "ugyldig personlig cipherpreferanser\n"
+msgstr "ugyldig personlig oppsett av krypteringsmetode\n"
 
 msgid "invalid personal digest preferences\n"
-msgstr "ugyldig personlig digestpreferanser\n"
+msgstr "ugyldig personlig oppsett av kontrollsummetode\n"
 
 msgid "invalid personal compress preferences\n"
-msgstr "ugyldig personlig kompresjonspreferanser\n"
+msgstr "ugyldig personlig oppsett av komprimeringsmetode\n"
 
 #, c-format
 msgid "%s does not yet work with %s\n"
-msgstr "%s virker ikke en med %s\n"
+msgstr "%s virker ikke enda med %s\n"
 
-#, fuzzy, c-format
-#| msgid "you may not use cipher algorithm `%s' while in %s mode\n"
+#, c-format
 msgid "you may not use cipher algorithm '%s' while in %s mode\n"
-msgstr "du kan ikke bruke cipheralgoritmen «%s» i %s-modus\n"
+msgstr "du kan ikke bruke krypteringsalgoritme Â«%s» i %s-modus\n"
 
-#, fuzzy, c-format
-#| msgid "you may not use digest algorithm `%s' while in %s mode\n"
+#, c-format
 msgid "you may not use digest algorithm '%s' while in %s mode\n"
-msgstr "du kan ikke bruke digestalgoritmen «%s» i %s-modus\n"
+msgstr "du kan ikke bruke summeringsalgoritme Â«%s» i %s-modus\n"
 
-#, fuzzy, c-format
-#| msgid "you may not use compression algorithm `%s' while in %s mode\n"
+#, c-format
 msgid "you may not use compression algorithm '%s' while in %s mode\n"
-msgstr "du kan ikke bruke kompresjonsalgoritmen «%s» i %s-modus\n"
+msgstr "du kan ikke bruke komprimeringsalgoritme «%s» i «%s»-modus\n"
 
 #, c-format
 msgid "failed to initialize the TrustDB: %s\n"
-msgstr "klarte ikke å initialisere tillitsdatabasen: %s\n"
+msgstr "klarte ikke å starte tillitsdatabase (TrustDB): %s\n"
 
 msgid "WARNING: recipients (-r) given without using public key encryption\n"
-msgstr ""
-"ADVARSEL: mottakere (-r) angitt uten å bruke offentlig nøkkelkryptering\n"
+msgstr "ADVARSEL: mottakere (-r) valgt uten offentlig nøkkelkryptering\n"
 
 msgid "--store [filename]"
 msgstr "--store [filnavn]"
@@ -2406,10 +2263,9 @@ msgstr "--store [filnavn]"
 msgid "--symmetric [filename]"
 msgstr "--symmetric [filnavn]"
 
-#, fuzzy, c-format
-#| msgid "symmetric encryption of `%s' failed: %s\n"
+#, c-format
 msgid "symmetric encryption of '%s' failed: %s\n"
-msgstr "symmetrisk kryptering av «%s» mislyktes: %s\n"
+msgstr "symmetrisk kryptering av Â«%s» mislyktes: %s\n"
 
 msgid "--encrypt [filename]"
 msgstr "--encrypt [filnavn]"
@@ -2418,11 +2274,11 @@ msgid "--symmetric --encrypt [filename]"
 msgstr "--symmetric --encrypt [filnavn]"
 
 msgid "you cannot use --symmetric --encrypt with --s2k-mode 0\n"
-msgstr ""
+msgstr "du kan ikke bruke «--symmetric --encrypt» og «--s2k-mode 0» samtidig\n"
 
 #, c-format
 msgid "you cannot use --symmetric --encrypt while in %s mode\n"
-msgstr "du kan ikke bruke --symmtric --encrypt i %s-modus\n"
+msgstr "du kan ikke velge «--symmtric» og «--encrypt» i «%s»-modus\n"
 
 msgid "--sign [filename]"
 msgstr "--sign [filnavn]"
@@ -2435,10 +2291,11 @@ msgstr "--symmetric --sign --encrypt [filnavn]"
 
 msgid "you cannot use --symmetric --sign --encrypt with --s2k-mode 0\n"
 msgstr ""
+"du kan ikke bruke «--symmetric --sign --encrypt» og «--s2k-mode 0» samtidig\n"
 
 #, c-format
 msgid "you cannot use --symmetric --sign --encrypt while in %s mode\n"
-msgstr "du kan ikke bruke --symmetric --sign --encrypt i %s-modus\n"
+msgstr "du kan ikke velge «--symmtric», «--sign» og «--encrypt» i «%s»-modus\n"
 
 msgid "--sign --symmetric [filename]"
 msgstr "--sign --symmetric [filnavn]"
@@ -2450,42 +2307,40 @@ msgid "--decrypt [filename]"
 msgstr "--decrypt [filnavn]"
 
 msgid "--sign-key user-id"
-msgstr "--sign-key brukerid"
+msgstr "--sign-key bruker-ID"
 
 msgid "--lsign-key user-id"
-msgstr "--lsign-key brukerid"
+msgstr "--lsign-key bruker-ID"
 
 msgid "--edit-key user-id [commands]"
-msgstr "--edit-key brukerid [kommandoer]"
+msgstr "--edit-key bruker-ID [kommandoer]"
 
-#, fuzzy
 msgid "--passwd <user-id>"
-msgstr "--sign-key brukerid"
+msgstr "--passwd <bruker-id>"
 
 #, c-format
 msgid "keyserver send failed: %s\n"
-msgstr "sending til nøkkelserver mislyktes: %s\n"
+msgstr "sending til nøkkeltjener mislyktes: %s\n"
 
 #, c-format
 msgid "keyserver receive failed: %s\n"
-msgstr "mottak fra nøkkelserver mislyktes: %s\n"
+msgstr "mottak fra nøkkeltjener mislyktes: %s\n"
 
 #, c-format
 msgid "key export failed: %s\n"
-msgstr "nøkkeleksport mislyktes: %s\n"
+msgstr "nøkkeleksport mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "key export failed: %s\n"
+#, c-format
 msgid "export as ssh key failed: %s\n"
-msgstr "nøkkeleksport mislyktes: %s\n"
+msgstr "eksportering som ssh-nøkkel mislyktes: %s\n"
 
 #, c-format
 msgid "keyserver search failed: %s\n"
-msgstr "søk på nøkkelserver mislyktes: %s\n"
+msgstr "søk på nøkkeltjener mislyktes: %s\n"
 
 #, c-format
 msgid "keyserver refresh failed: %s\n"
-msgstr "refresh på nøkkelserver mislyktes: %s\n"
+msgstr "oppdatering av nøkkeltjener mislyktes: %s\n"
 
 #, c-format
 msgid "dearmoring failed: %s\n"
@@ -2495,86 +2350,91 @@ msgstr "dearmoring failed: %s\n"
 msgid "enarmoring failed: %s\n"
 msgstr "enarmoring failed: %s\n"
 
-#, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
+#, c-format
 msgid "invalid hash algorithm '%s'\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "«%s» er en ugyldig summeringsalgoritme\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error parsing key specification '%s': %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under tolking av nøkkelspesifikasjon «%s»: %s\n"
 
 #, c-format
 msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
 msgstr ""
+"«%s» ser hverken ut til å være en gyldig nøkkel-ID, fingeravtrykk eller "
+"nøkkelgrep\n"
 
 msgid "[filename]"
 msgstr "[filnavn]"
 
 msgid "Go ahead and type your message ...\n"
-msgstr "Sett i gang og tast inn meldingen din ...\n"
+msgstr "Skriv inn melding …\n"
 
 msgid "the given certification policy URL is invalid\n"
-msgstr "den angitte URLen for sertifikasjonspolicyen er ugyldig\n"
+msgstr "valgt adresse for sertifikasjonsregler er ugyldig\n"
 
 msgid "the given signature policy URL is invalid\n"
-msgstr "den angitte URLen for signaturpolicy er ugyldig\n"
+msgstr "valgt adresse for signaturregler er ugyldig\n"
 
 msgid "the given preferred keyserver URL is invalid\n"
-msgstr "den angitte URLen for den foretrukkede nøkkelserveren er ugyldig\n"
+msgstr "valgt adresse for foretrukket nøkkeltjener er ugyldig\n"
 
-#, fuzzy
 msgid "|FILE|take the keys from the keyring FILE"
-msgstr "hent nøklene fra dette nøkkelknippet"
+msgstr "|FIL|hent nøkler fra valgt nøkkelknippe-FIL"
 
 msgid "make timestamp conflicts only a warning"
-msgstr "la konflikter mellom tidsstempler bare være en advarsel"
+msgstr "la konflikter mellom tidsstempler bare være en advarsel"
 
 msgid "|FD|write status info to this FD"
 msgstr "|FD|skrive statusinfo til denne FD"
 
 msgid "|ALGO|reject signatures made with ALGO"
-msgstr ""
+msgstr "|ALGO|avvis signaturer som er laget med valgt ALGOritme"
 
 msgid "Usage: gpgv [options] [files] (-h for help)"
-msgstr "Bruksmåte: gpgv [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: gpgv [valg] [filer] (-h for hjelp)"
 
-#, fuzzy
 msgid ""
 "Syntax: gpgv [options] [files]\n"
 "Check signatures against known trusted keys\n"
 msgstr ""
-"Bruksmåte: gpgv [valg] [filer]\n"
-"Sjekke signaturer mot kjente betrodde nøkler\n"
+"Syntaks: gpgv [valg] [filer]\n"
+"Kontroller signaturer mot kjente troverdige nøkler\n"
 
 msgid "No help available"
-msgstr ""
+msgstr "Ingen hjelp tilgjengelig"
 
 #, c-format
 msgid "No help available for '%s'"
-msgstr ""
+msgstr "Ingen hjelp tilgjengelig for «%s»"
 
 msgid "import signatures that are marked as local-only"
-msgstr ""
+msgstr "importer signaturer som er merket som kun lokale"
 
 msgid "repair damage from the pks keyserver during import"
-msgstr ""
+msgstr "reparer skader fra pks-nøkkeltjener under importering"
 
-#, fuzzy
-#| msgid "do not update the trustdb after import"
 msgid "do not clear the ownertrust values during import"
-msgstr "ikke oppdatér tillitsdatabasen etter import"
+msgstr "ikke tøm «ownertrust»-verdier under importering"
 
 msgid "do not update the trustdb after import"
-msgstr "ikke oppdatér tillitsdatabasen etter import"
+msgstr "ikke oppdater tillitsdatabase etter importering"
+
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "vise nøkkelens fingeravtrykk"
 
 msgid "only accept updates to existing keys"
-msgstr ""
+msgstr "bare godta oppdateringer av nøkler som finnes allerede"
 
 msgid "remove unusable parts from key after import"
-msgstr ""
+msgstr "fjern ubrukelige deler av nøkkel etter importering"
 
 msgid "remove as much as possible from key after import"
+msgstr "fjern så mye som mulig fra nøkkel etter importering"
+
+msgid "run import filters and export key immediately"
 msgstr ""
 
 #, c-format
@@ -2583,234 +2443,230 @@ msgstr "hopper over blokk av typen %d\n"
 
 #, c-format
 msgid "%lu keys processed so far\n"
-msgstr "%lu nøkler behandlet hittil\n"
+msgstr "%lu nøkler behandlet hittil\n"
 
 #, c-format
 msgid "Total number processed: %lu\n"
 msgstr "Totalt antall behandlet: %lu\n"
 
-#, fuzzy, c-format
-#| msgid "      skipped new keys: %lu\n"
+#, c-format
 msgid "    skipped PGP-2 keys: %lu\n"
-msgstr "nye nøkler som ble hoppet over: %lu\n"
+msgstr "    hopper over PGP 2-nøkler: %lu\n"
 
 #, c-format
 msgid "      skipped new keys: %lu\n"
-msgstr "nye nøkler som ble hoppet over: %lu\n"
+msgstr "      nye nøkler som ble hoppet over: %lu\n"
 
 #, c-format
 msgid "          w/o user IDs: %lu\n"
-msgstr "               uten brukerider: %lu\n"
+msgstr "          uten bruker-id-er: %lu\n"
 
 #, c-format
 msgid "              imported: %lu"
-msgstr "                     importert: %lu"
+msgstr "              importert: %lu"
 
 #, c-format
 msgid "             unchanged: %lu\n"
-msgstr "                       uendret: %lu\n"
+msgstr "             uendret: %lu\n"
 
 #, c-format
 msgid "          new user IDs: %lu\n"
-msgstr "                nye brukerider: %lu\n"
+msgstr "          nye bruker-id-er: %lu\n"
 
 #, c-format
 msgid "           new subkeys: %lu\n"
-msgstr "               nye undernøkler: %lu\n"
+msgstr "           nye undernøkler: %lu\n"
 
 #, c-format
 msgid "        new signatures: %lu\n"
-msgstr "                nye signaturer: %lu\n"
+msgstr "        nye signaturer: %lu\n"
 
 #, c-format
 msgid "   new key revocations: %lu\n"
-msgstr "         nye nøkkelopphevinger: %lu\n"
+msgstr "   nye nøkkelopphevinger: %lu\n"
 
 #, c-format
 msgid "      secret keys read: %lu\n"
-msgstr "        leste hemmelige nøkler: %lu\n"
+msgstr "      leste hemmelige nøkler: %lu\n"
 
 #, c-format
 msgid "  secret keys imported: %lu\n"
-msgstr "   importerte hemmelige nøkler: %lu\n"
+msgstr "  importerte hemmelige nøkler: %lu\n"
 
 #, c-format
 msgid " secret keys unchanged: %lu\n"
-msgstr "  uforandrede hemmelige nøkler: %lu\n"
+msgstr " uforandrede hemmelige nøkler: %lu\n"
 
 #, c-format
 msgid "          not imported: %lu\n"
-msgstr "                ikke importert: %lu\n"
+msgstr "          ikke importert: %lu\n"
 
 #, c-format
 msgid "    signatures cleaned: %lu\n"
-msgstr "         oppryddete signaturer: %lu\n"
+msgstr "    oppryddete signaturer: %lu\n"
 
 #, c-format
 msgid "      user IDs cleaned: %lu\n"
-msgstr "         oppryddete brukerider: %lu\n"
+msgstr "      tømte bruker-id-er: %lu\n"
 
 #, c-format
 msgid ""
 "WARNING: key %s contains preferences for unavailable\n"
 "algorithms on these user IDs:\n"
 msgstr ""
+"ADVARSEL: nøkkelen %s inneholder innstillinger for\n"
+"utilgjengelige algoritmer på følgende bruker-id-er:\n"
 
 #, c-format
 msgid "         \"%s\": preference for cipher algorithm %s\n"
-msgstr ""
+msgstr "         «%s»: innstilling for krypteringsalgoritme %s\n"
 
 #, c-format
 msgid "         \"%s\": preference for digest algorithm %s\n"
-msgstr "         «%s» preferanse for digestalgoritme %s\n"
+msgstr "         «%s»: oppsett for kontrollsum-algoritme %s\n"
 
 #, c-format
 msgid "         \"%s\": preference for compression algorithm %s\n"
-msgstr ""
+msgstr "         «%s»: oppsett av komprimeringsalgoritme %s\n"
 
 msgid "it is strongly suggested that you update your preferences and\n"
-msgstr ""
+msgstr "du anbefales på det sterkeste å endre oppsett og\n"
 
 msgid "re-distribute this key to avoid potential algorithm mismatch problems\n"
 msgstr ""
+"dele ut denne nøkkelen på nytt for å unngå potensielle problemer med "
+"algoritme-samsvar\n"
 
 #, c-format
 msgid "you can update your preferences with: gpg --edit-key %s updpref save\n"
 msgstr ""
+"oppdater oppsettet med følgende kommando: gpg --edit-key %s updpref save\n"
 
 #, c-format
 msgid "key %s: no user ID\n"
-msgstr "nøkkel %s: ingen brukerid\n"
+msgstr "nøkkel %s: ingen bruker-ID\n"
 
-#, fuzzy, c-format
-#| msgid "skipped \"%s\": %s\n"
+#, c-format
 msgid "key %s: %s\n"
-msgstr "hoppet over «%s»: %s\n"
+msgstr "nøkkel %s: %s\n"
 
 msgid "rejected by import screener"
-msgstr ""
+msgstr "avvist av importeringskontrollør"
 
 #, c-format
 msgid "key %s: PKS subkey corruption repaired\n"
-msgstr "nøkkel %s: PKS-undernøkkel reparert\n"
+msgstr "nøkkel %s: PKS-undernøkkel reparert\n"
 
 #, c-format
 msgid "key %s: accepted non self-signed user ID \"%s\"\n"
-msgstr "nøkkel %s: akseptert ikke-selvsignert brukerid «%s»\n"
+msgstr "nøkkel %s: akseptert ikke-selvsignert bruker-ID Â«%s»\n"
 
 #, c-format
 msgid "key %s: no valid user IDs\n"
-msgstr "nøkkel %s: ingen gyldig brukerid\n"
+msgstr "nøkkel %s: ingen gyldig bruker-id-er\n"
 
 msgid "this may be caused by a missing self-signature\n"
-msgstr "dette kan skyldes en manglende selvsignatur\n"
+msgstr "dette kan skyldes manglende selvsignatur\n"
 
 #, c-format
 msgid "key %s: public key not found: %s\n"
-msgstr "nøkkel %s: offentlig nøkkel ikke funnet: %s\n"
+msgstr "nøkkel %s: fant ikke offentlig nøkkel. %s\n"
 
 #, c-format
 msgid "key %s: new key - skipped\n"
-msgstr "nøkkel %s: ny nøkkel - hoppet over\n"
+msgstr "nøkkel %s: ny nøkkel. Hoppet over\n"
 
 #, c-format
 msgid "no writable keyring found: %s\n"
-msgstr "ingen skrivbart nøkkelknippe funnet: %s\n"
-
-#, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "skriver til «%s»\n"
+msgstr "fant ikke skrivbart nøkkelknippe. %s\n"
 
-#, fuzzy, c-format
-#| msgid "error writing keyring `%s': %s\n"
+#, c-format
 msgid "error writing keyring '%s': %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under skriving av nøkkelknippe Â«%s»: %s\n"
 
 #, c-format
 msgid "key %s: public key \"%s\" imported\n"
-msgstr "nøkkel %s: offentlig nøkkel «%s» importert\n"
+msgstr "nøkkel %s: offentlig nøkkel Â«%s» importert\n"
 
 #, c-format
 msgid "key %s: doesn't match our copy\n"
-msgstr "nøkkel %s: stemmer ikke med vår kopi\n"
+msgstr "nøkkel %s: stemmer ikke med vår kopi\n"
 
 #, c-format
 msgid "key %s: can't locate original keyblock: %s\n"
-msgstr "nøkkel %s: kan ikke finne original nøkkelblokk: %s\n"
+msgstr "nøkkel %s: finner ikke original nøkkelblokk: %s\n"
 
 #, c-format
 msgid "key %s: can't read original keyblock: %s\n"
-msgstr "nøkkel %s: kan ikke lese original nøkkelblokk: %s\n"
+msgstr "nøkkel %s: klarte ikke å lese opprinnelig nøkkelblokk. %s\n"
 
 #, c-format
 msgid "key %s: \"%s\" 1 new user ID\n"
-msgstr "nøkkel %s: «%s» 1 ny brukerid\n"
+msgstr "nøkkel %s: «%s» 1 ny bruker-ID\n"
 
 #, c-format
 msgid "key %s: \"%s\" %d new user IDs\n"
-msgstr "nøkkel %s: «%s» %d nye brukerider\n"
+msgstr "nøkkel %s: «%s» %d nye bruker-id-er\n"
 
 #, c-format
 msgid "key %s: \"%s\" 1 new signature\n"
-msgstr "nøkkel %s: «%s» 1 ny signatur\n"
+msgstr "nøkkel %s: Â«%s» 1 ny signatur\n"
 
 #, c-format
 msgid "key %s: \"%s\" %d new signatures\n"
-msgstr "nøkkel: %s: «%s» %d nye signaturer\n"
+msgstr "nøkkel: %s: Â«%s» %d nye signaturer\n"
 
 #, c-format
 msgid "key %s: \"%s\" 1 new subkey\n"
-msgstr "nøkkel %s: «%s» 1 ny undernøkkel\n"
+msgstr "nøkkel %s: «%s» 1 ny undernøkkel\n"
 
 #, c-format
 msgid "key %s: \"%s\" %d new subkeys\n"
-msgstr "nøkkel %s: «%s» %d nye undernøkler\n"
+msgstr "nøkkel %s: «%s» %d nye undernøkler\n"
 
 #, c-format
 msgid "key %s: \"%s\" %d signature cleaned\n"
-msgstr "nøkkel: %s: «%s» %d nye signaturer\n"
+msgstr "nøkkel: %s: Â«%s» %d nye signaturer\n"
 
 #, c-format
 msgid "key %s: \"%s\" %d signatures cleaned\n"
-msgstr "nøkkel: %s: «%s» %d nye signaturer\n"
+msgstr "nøkkel: %s: Â«%s» %d nye signaturer\n"
 
 #, c-format
 msgid "key %s: \"%s\" %d user ID cleaned\n"
-msgstr "nøkkel %s: «%s» %d nye brukerider\n"
+msgstr "nøkkel %s: «%s» %d nye bruker-id-er\n"
 
 #, c-format
 msgid "key %s: \"%s\" %d user IDs cleaned\n"
-msgstr "nøkkel %s: «%s» %d nye brukerider\n"
+msgstr "nøkkel %s: «%s» %d nye bruker-id-er\n"
 
 #, c-format
 msgid "key %s: \"%s\" not changed\n"
-msgstr "nøkkel %s: «%s» ikke endret\n"
+msgstr "nøkkel %s: Â«%s» ikke endret\n"
 
 #, c-format
 msgid "key %s: secret key imported\n"
-msgstr "nøkkel %s: hemmelig nøkkel importert\n"
+msgstr "nøkkel %s: hemmelig nøkkel importert\n"
 
-#, fuzzy, c-format
-#| msgid "key %s: secret key imported\n"
+#, c-format
 msgid "key %s: secret key already exists\n"
-msgstr "nøkkel %s: hemmelig nøkkel importert\n"
+msgstr "nøkkel %s: hemmelig nøkkel finnes allerede\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "key %s: error sending to agent: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "nøkkel %s: feil under sending til agent: %s\n"
 
-#, fuzzy, c-format
-#| msgid "secret key \"%s\" not found: %s\n"
+#, c-format
 msgid "secret key %s: %s\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "hemmelig nøkkel %s: %s\n"
 
 msgid "importing secret keys not allowed\n"
-msgstr "import av hemmelig nøkkel er ikke tillatt\n"
+msgstr "importering av hemmelig nøkkel er ikke tillatt\n"
 
 #, c-format
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
-msgstr "nøkkel %s: hemmelig nøkkel med ugyldig cipher %d - hoppet over\n"
+msgstr ""
+"nøkkel %s: hemmelig nøkkel med ugyldig krypteringsmetode %d - hoppet over\n"
 
 #. TRANSLATORS: For smartcard, each private key on
 #. host has a reference (stub) to a smartcard and
@@ -2824,144 +2680,143 @@ msgstr "n
 #. created again.
 #, c-format
 msgid "To migrate '%s', with each smartcard, run: %s\n"
-msgstr ""
+msgstr "Kjør følgende kommando for å flytte «%s»: %s\n"
 
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
-"nøkkel %s: ingen offentlig nøkkel - kan ikke anvende opphevingssertifikat\n"
+"nøkkel %s: offentlig nøkkel mangler. Klarte ikke å bruke "
+"opphevelsessertifikat\n"
 
 #, c-format
 msgid "key %s: invalid revocation certificate: %s - rejected\n"
-msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - avvist\n"
+msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - avvist\n"
 
 #, c-format
 msgid "key %s: \"%s\" revocation certificate imported\n"
-msgstr "nøkkel %s: «%s» opphevingssertifikat importert\n"
+msgstr "nøkkel %s: Â«%s» opphevingssertifikat importert\n"
 
 #, c-format
 msgid "key %s: no user ID for signature\n"
-msgstr "nøkkel %s: ingen brukerid for signatur\n"
+msgstr "nøkkel %s: ingen bruker-ID for signatur\n"
 
 #, c-format
 msgid "key %s: unsupported public key algorithm on user ID \"%s\"\n"
-msgstr "nøkkel %s: ustøttet offentlig nøkkelalgoritme for brukerid «%s»\n"
+msgstr ""
+"nøkkel %s: offentlig nøkkelalgoritme for bruker-ID («%s») støttes ikke\n"
 
 #, c-format
 msgid "key %s: invalid self-signature on user ID \"%s\"\n"
-msgstr "nøkkel %s: ugyldig selvsignatur for brukerid «%s»\n"
+msgstr "nøkkel %s: ugyldig selvsignatur for bruker-ID Â«%s»\n"
 
 #, c-format
 msgid "key %s: unsupported public key algorithm\n"
-msgstr "nøkkel %s: ustøttet offentlig nøkkelalgoritme\n"
+msgstr "nøkkel %s: ustøttet offentlig nøkkelalgoritme\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "key %s: invalid direct key signature\n"
-msgstr "nøkkel %s: direkte nøkkelsignatur lagt til\n"
+msgstr "nøkkel %s: ugyldig direkte nøkkelsignatur\n"
 
 #, c-format
 msgid "key %s: no subkey for key binding\n"
-msgstr "nøkkel %s: ingen undernøkkel for nøkkelbinding\n"
+msgstr "nøkkel %s: ingen undernøkkel for nøkkelbinding\n"
 
 #, c-format
 msgid "key %s: invalid subkey binding\n"
-msgstr "nøkkel %s: ugyldig undernøkkelbinding\n"
+msgstr "nøkkel %s: ugyldig undernøkkelbinding\n"
 
 #, c-format
 msgid "key %s: removed multiple subkey binding\n"
-msgstr "nøkkel %s: fjernet flere undernøkkelbindinger\n"
+msgstr "nøkkel %s: fjernet flere undernøkkelbindinger\n"
 
 #, c-format
 msgid "key %s: no subkey for key revocation\n"
-msgstr "nøkkel %s: ingen undernøkkel for nøkkeloppheving\n"
+msgstr "nøkkel %s: ingen undernøkkel for nøkkeloppheving\n"
 
 #, c-format
 msgid "key %s: invalid subkey revocation\n"
-msgstr "nøkkel %s: ugyldig undernøkkeloppheving\n"
+msgstr "nøkkel %s: ugyldig undernøkkeloppheving\n"
 
 #, c-format
 msgid "key %s: removed multiple subkey revocation\n"
-msgstr "nøkkel %s: fjernet flere undernøkkelopphevinger\n"
+msgstr "nøkkel %s: fjernet flere undernøkkelopphevinger\n"
 
 #, c-format
 msgid "key %s: skipped user ID \"%s\"\n"
-msgstr "nøkkel %s: hoppet over brukerid «%s»\n"
+msgstr "nøkkel %s: hoppet over bruker-ID Â«%s»\n"
 
 #, c-format
 msgid "key %s: skipped subkey\n"
-msgstr "nøkkel %s: hoppet over undernøkkel\n"
+msgstr "nøkkel %s: hoppet over undernøkkel\n"
 
 #, c-format
 msgid "key %s: non exportable signature (class 0x%02X) - skipped\n"
-msgstr "nøkkel %s: ikke-eksporterbar signatur (klasse 0x%02X) - hoppet over\n"
+msgstr "nøkkel %s: ikke-eksporterbar signatur (klasse 0x%02X) - hoppet over\n"
 
 #, c-format
 msgid "key %s: revocation certificate at wrong place - skipped\n"
-msgstr "nøkkel %s: opphevingssertifikat på feil plass - hoppet over\n"
+msgstr "nøkkel %s: opphevingssertifikat på feil plass - hoppet over\n"
 
 #, c-format
 msgid "key %s: invalid revocation certificate: %s - skipped\n"
-msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - hoppet over\n"
+msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - hoppet over\n"
 
 #, c-format
 msgid "key %s: subkey signature in wrong place - skipped\n"
-msgstr "nøkkel %s: undernøkkelsignatur på feil plass - hoppet over\n"
+msgstr "nøkkel %s: undernøkkelsignatur på feil plass - hoppet over\n"
 
 #, c-format
 msgid "key %s: unexpected signature class (0x%02X) - skipped\n"
-msgstr "nøkkel %s: uforventet signaturklasse (0x%02X) - hoppet over\n"
+msgstr "nøkkel %s: uforventet signaturklasse (0x%02X) - hoppet over\n"
 
 #, c-format
 msgid "key %s: duplicated user ID detected - merged\n"
-msgstr "nøkkel %s: duplikert brukerid oppdaget - flettet sammen\n"
+msgstr "nøkkel %s: oppdaget duplisert bruker-ID. Slått sammen\n"
 
 #, c-format
 msgid "WARNING: key %s may be revoked: fetching revocation key %s\n"
-msgstr "ADVARSEL: nøkkel %s kan være opphevet: henter opphevingsnøkkel %s\n"
+msgstr "ADVARSEL: nøkkel %s kan være opphevet: henter opphevingsnøkkel %s\n"
 
 #, c-format
 msgid "WARNING: key %s may be revoked: revocation key %s not present.\n"
 msgstr ""
-"ADVARSEL: nøkkel %s kan være opphevet: opphevingsnøkkel %s ikke tilstede.\n"
+"ADVARSEL: nøkkel %s kan være opphevet: opphevingsnøkkel %s ikke tilstede.\n"
 
 #, c-format
 msgid "key %s: \"%s\" revocation certificate added\n"
-msgstr "nøkkel %s: «%s» opphevingssertifikat lagt til\n"
+msgstr "nøkkel %s: Â«%s» opphevingssertifikat lagt til\n"
 
 #, c-format
 msgid "key %s: direct key signature added\n"
-msgstr "nøkkel %s: direkte nøkkelsignatur lagt til\n"
+msgstr "nøkkel %s: direkte nøkkelsignatur lagt til\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error creating keybox '%s': %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "feil under opprettelse av nøkkelskrin Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error creating keyring `%s': %s\n"
+#, c-format
 msgid "error creating keyring '%s': %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "feil under opprettelse av nøkkelknippe Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "keybox '%s' created\n"
-msgstr "nøkkelknippet «%s» ble opprettet\n"
+msgstr "nøkkelskrin «%s» er opprettet\n"
 
-#, fuzzy, c-format
-#| msgid "keyring `%s' created\n"
+#, c-format
 msgid "keyring '%s' created\n"
-msgstr "nøkkelknippet «%s» ble opprettet\n"
+msgstr "nøkkelknippe «%s» er opprettet\n"
 
-#, fuzzy, c-format
-#| msgid "keyblock resource `%s': %s\n"
+#, c-format
 msgid "keyblock resource '%s': %s\n"
-msgstr "nøkkelblokkressurs «%s»: %s\n"
+msgstr "nøkkelblokkressurs Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error opening key DB: %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under åpning av nøkkeldatabase: %s\n"
 
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
-msgstr ""
+msgstr "klarte ikke å bygge hurtiglager for nøkkelknippe på nytt. %s\n"
 
 msgid "[revocation]"
 msgstr "[oppheving]"
@@ -2969,57 +2824,57 @@ msgstr "[oppheving]"
 msgid "[self-signature]"
 msgstr "[selvsignatur]"
 
-#, fuzzy, c-format
-#| msgid "key %s: unsupported public key algorithm\n"
+#, c-format
 msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
-msgstr "nøkkel %s: ustøttet offentlig nøkkelalgoritme\n"
+msgstr ""
+"klarte ikke å kontrollere signatur på grunn av ustøttet algoritme for "
+"offentlig nøkkel (%d): %s.\n"
 
-#, fuzzy, c-format
-#| msgid "card does not support digest algorithm %s\n"
+#, c-format
 msgid ""
 "can't check signature with unsupported message-digest algorithm %d: %s.\n"
-msgstr "kortet støtter ikke digestalgoritme %s\n"
+msgstr ""
+"klarte ikke å kontrollere signatur på grunn av ustøttet algoritme for "
+"meldingssum (%d): %s.\n"
 
-#, fuzzy
 msgid " (reordered signatures follow)"
-msgstr "God signatur fra «%s»"
+msgstr " (omsorterte signaturer følger)"
 
-#, fuzzy, c-format
-#| msgid "skipped \"%s\": %s\n"
+#, c-format
 msgid "key %s:\n"
-msgstr "hoppet over «%s»: %s\n"
+msgstr "nøkkel %s:\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%d duplicate signature removed\n"
 msgid_plural "%d duplicate signatures removed\n"
-msgstr[0] "nøkkel: %s: «%s» %d nye signaturer\n"
-msgstr[1] "nøkkel: %s: «%s» %d nye signaturer\n"
+msgstr[0] "%d duplikatsignatur fjernet\n"
+msgstr[1] "%d duplikatsignaturer fjernet\n"
 
-#, fuzzy, c-format
-#| msgid "1 signature not checked due to a missing key\n"
+#, c-format
 msgid "%d signature not checked due to a missing key\n"
 msgid_plural "%d signatures not checked due to missing keys\n"
-msgstr[0] "1 signatur ble ikke sjekket på grunn av en manglende nøkkel\n"
-msgstr[1] "1 signatur ble ikke sjekket på grunn av en manglende nøkkel\n"
+msgstr[0] "%d signatur ble ikke kontrollert på grunn av manglende nøkkel\n"
+msgstr[1] "%d signaturer ble ikke kontrollert på grunn av manglende nøkkel\n"
 
-#, fuzzy, c-format
-#| msgid "%d bad signatures\n"
+#, c-format
 msgid "%d bad signature\n"
 msgid_plural "%d bad signatures\n"
-msgstr[0] "%d ubrukelige signaturer\n"
+msgstr[0] "%d ubrukelig signatur\n"
 msgstr[1] "%d ubrukelige signaturer\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%d signature reordered\n"
 msgid_plural "%d signatures reordered\n"
-msgstr[0] "God signatur fra «%s»"
-msgstr[1] "God signatur fra «%s»"
+msgstr[0] "%d signatur omsortert\n"
+msgstr[1] "%d signaturer omsortert\n"
 
 #, c-format
 msgid ""
 "Warning: errors found and only checked self-signatures, run '%s' to check "
 "all signatures.\n"
 msgstr ""
+"Advarsel: fant feil og kontrollerte bare selvsignaturer. Kjør «%s» for å "
+"kontrollere alle signaturer.\n"
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3027,8 +2882,8 @@ msgid ""
 "(by looking at passports, checking fingerprints from different sources, "
 "etc.)\n"
 msgstr ""
-"Vennligst bestem hvor mye du tiltror denne brukeren korrekt å bekrefte\n"
-"andre brukeres nøkler (ved å se på pass, sjekke fingeravtrykk fra\n"
+"Velg hvor mye du stoler på at denne brukeren kan bekrefte\n"
+"andre brukeres nøkler (ved å se på pass, sjekke fingeravtrykk fra\n"
 "forskjellige kilder, osv.)\n"
 
 #, c-format
@@ -3044,35 +2899,40 @@ msgid ""
 "A depth greater than 1 allows the key you are signing to make\n"
 "trust signatures on your behalf.\n"
 msgstr ""
+"Skriv inn dybden av tillit du vil erklære med denne signaturen.\n"
+"En dybde på over 1 tillater at nøkkelen du signerer\n"
+"lager tillitssignaturer på dine vegne.\n"
 
 msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
+"Skriv inn et domene som denne signaturen skal begrenses til, eller trykk "
+"enter hvis ingen.\n"
 
 #, c-format
 msgid "Skipping user ID \"%s\", which is not a text ID.\n"
-msgstr ""
+msgstr "Hopper over bruker-ID «%s», som ikke er en tekst-iD.\n"
 
 #, c-format
 msgid "User ID \"%s\" is revoked."
-msgstr "Brukerid «%s» er opphevet."
+msgstr "Bruker-ID Â«%s» er opphevet."
 
 msgid "Are you sure you still want to sign it? (y/N) "
-msgstr "Er du fortsatt sikker på at du vil signerere den? (j/N) "
+msgstr "Er du sikker på at du vil signerere den? (j/N) "
 
 msgid "  Unable to sign.\n"
-msgstr "  Kunne ikke signere.\n"
+msgstr "  Klarte ikke å signere.\n"
 
 #, c-format
 msgid "User ID \"%s\" is expired."
-msgstr "Brukerid «%s» er utgått."
+msgstr "Bruker-ID «%s» er utgått."
 
 #, c-format
 msgid "User ID \"%s\" is not self-signed."
-msgstr "Brukeriden «%s» er ikke selvsignert."
+msgstr "Bruker-ID Â«%s» er ikke selvsignert."
 
 #, c-format
 msgid "User ID \"%s\" is signable.  "
-msgstr "Brukeriden «%s» er signerbar."
+msgstr "Bruker-ID «%s» er signerbar.  "
 
 msgid "Sign it? (y/N) "
 msgstr "Signere den? (j/N) "
@@ -3082,7 +2942,7 @@ msgid ""
 "The self-signature on \"%s\"\n"
 "is a PGP 2.x-style signature.\n"
 msgstr ""
-"Selvsignaturen på «%s»\n"
+"Selvsignaturen pÃ¥ Â«%s»\n"
 "er en PGP 2.x-aktig signatur.\n"
 
 msgid "Do you want to promote it to an OpenPGP self-signature? (y/N) "
@@ -3093,18 +2953,18 @@ msgid ""
 "Your current signature on \"%s\"\n"
 "has expired.\n"
 msgstr ""
-"Din nåværende signatur på «%s»\n"
-"er utgått.\n"
+"Gjeldende signatur pÃ¥ Â«%s»\n"
+"er utgått.\n"
 
 msgid "Do you want to issue a new signature to replace the expired one? (y/N) "
-msgstr "Vil du utstede en ny signatur for å erstatte den som er utgått? (j/N) "
+msgstr "Vil du utstede en ny signatur for å erstatte den som er utgått? (j/N) "
 
 #, c-format
 msgid ""
 "Your current signature on \"%s\"\n"
 "is a local signature.\n"
 msgstr ""
-"Din nåværede signatur på «%s»\n"
+"Din nÃ¥værede signatur pÃ¥ Â«%s»\n"
 "er en lokal signatur.\n"
 
 msgid "Do you want to promote it to a full exportable signature? (y/N) "
@@ -3112,36 +2972,36 @@ msgstr "Vil du forfremme den til en fullt eksporterbar signatur? (j/N) "
 
 #, c-format
 msgid "\"%s\" was already locally signed by key %s\n"
-msgstr "«%s» var allerede lokalt signert av nøkkelen %s\n"
+msgstr "«%s» var allerede lokalt signert med nøkkelen %s\n"
 
 #, c-format
 msgid "\"%s\" was already signed by key %s\n"
-msgstr "«%s» var allerede signert av nøkkelen %s\n"
+msgstr "«%s» var allerede signert med nøkkelen %s\n"
 
 msgid "Do you want to sign it again anyway? (y/N) "
-msgstr "Vil du likevel signere den igjen? (j/N) "
+msgstr "Vil du signere den på nytt likevel? (j/N) "
 
 #, c-format
 msgid "Nothing to sign with key %s\n"
-msgstr "Ingenting å signere med nøkkelen %s\n"
+msgstr "Ingenting å signere med nøkkelen %s\n"
 
 msgid "This key has expired!"
-msgstr "Denne nøkkelen er utgått!"
+msgstr "Denne nøkkelen er utgått."
 
 #, c-format
 msgid "This key is due to expire on %s.\n"
-msgstr "Denne nøkkelen utgår den %s.\n"
+msgstr "Denne nøkkelen utgår %s.\n"
 
 msgid "Do you want your signature to expire at the same time? (Y/n) "
-msgstr "Vil du at signaturen skal utgå på samme tidspunkt? (J/n) "
+msgstr "Vil du at signaturen skal utgå på samme tidspunkt? (J/n) "
 
 msgid ""
 "How carefully have you verified the key you are about to sign actually "
 "belongs\n"
 "to the person named above?  If you don't know what to answer, enter \"0\".\n"
 msgstr ""
-"Hvor nøyaktig har du bekreftet at nøkkelen du skal signere faktisk\n"
-"tilhører den overnevnte personen?  Tast inn «0» dersom du ikke vet\n"
+"Hvor nøyaktig har du bekreftet at nøkkelen du skal signere faktisk\n"
+"tilhører den overnevnte personen? Skriv «0» hvis du ikke vet\n"
 "svaret.\n"
 
 #, c-format
@@ -3158,47 +3018,45 @@ msgstr "   (2) Jeg har gjort en vanlig sjekk.%s\n"
 
 #, c-format
 msgid "   (3) I have done very careful checking.%s\n"
-msgstr "   (3) Jeg har sjekket veldig nøye.%s\n"
+msgstr "   (3) Jeg har sjekket veldig nøye.%s\n"
 
-#, fuzzy
-#| msgid "Your selection? (enter `?' for more information): "
 msgid "Your selection? (enter '?' for more information): "
-msgstr "Ditt valg? (angi «?» for mer informasjon): "
+msgstr "Hva velger du? (skriv Â«?» for mer informasjon): "
 
 #, c-format
 msgid ""
 "Are you sure that you want to sign this key with your\n"
 "key \"%s\" (%s)\n"
 msgstr ""
-"Er du virkelig sikker på at du vil signerere denne nøkkelen med din\n"
-"nøkkel «%s» (%s)\n"
+"Er du sikker på at du vil signerere denne nøkkelen med\n"
+"nøkkelen Â«%s» (%s)\n"
 
 msgid "This will be a self-signature.\n"
-msgstr "Dette vil være en selvsignatur.\n"
+msgstr "Dette skal være en selvsignatur.\n"
 
 msgid "WARNING: the signature will not be marked as non-exportable.\n"
-msgstr "ADVARSEL: signaturen vil ikke bli markert som ikke-eksporterbar.\n"
+msgstr "ADVARSEL: signaturen blir ikke markert som ikke-eksporterbar.\n"
 
 msgid "WARNING: the signature will not be marked as non-revocable.\n"
-msgstr "ADVARSEL: signaturen vil ikke bli markert som ikke-opphevbar.\n"
+msgstr "ADVARSEL: signaturen blir ikke markert som ikke-opphevbar.\n"
 
 msgid "The signature will be marked as non-exportable.\n"
-msgstr "Signaturen vil bli markert som ikke-eksporterbar.\n"
+msgstr "Signaturen blir markert som ikke-eksporterbar.\n"
 
 msgid "The signature will be marked as non-revocable.\n"
-msgstr "Signaturen vil bli markert som ikke-opphevbar.\n"
+msgstr "Signaturen blir markert som ikke-opphevbar.\n"
 
 msgid "I have not checked this key at all.\n"
-msgstr "Jeg har ikke sjekket denne nøkkelen i det hele tatt.\n"
+msgstr "Jeg har ikke sjekket denne nøkkelen i det hele tatt.\n"
 
 msgid "I have checked this key casually.\n"
-msgstr "Jeg har sjekket denne nøkkelen på vanlig måte.\n"
+msgstr "Jeg har sjekket denne nøkkelen på vanlig måte.\n"
 
 msgid "I have checked this key very carefully.\n"
-msgstr "Jeg har sjekket denne nøkkelen veldig nøye.\n"
+msgstr "Jeg har sjekket denne nøkkelen veldig nøye.\n"
 
 msgid "Really sign? (y/N) "
-msgstr "Virkelig signere? (j/N) "
+msgstr "Er du sikker på at du vil signere? (j/N) "
 
 #, c-format
 msgid "signing failed: %s\n"
@@ -3206,133 +3064,136 @@ msgstr "signering mislyktes: %s\n"
 
 msgid "Key has only stub or on-card key items - no passphrase to change.\n"
 msgstr ""
+"Nøkkelen har bare stubbe- eller kortnøkkel-elementer. Ingen passordfrase å "
+"endre.\n"
 
-#, fuzzy, c-format
-#| msgid "error creating passphrase: %s\n"
+#, c-format
 msgid "key %s: error changing passphrase: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "nøkkel %s: feil under endring av passordfrase: %s\n"
 
 msgid "save and quit"
 msgstr "lagre og avslutte"
 
 msgid "show key fingerprint"
-msgstr "vise nøkkelens fingeravtrykk"
+msgstr "vise nøkkelens fingeravtrykk"
 
-#, fuzzy
-#| msgid "show this help"
 msgid "show the keygrip"
-msgstr "vise denne hjelpen"
+msgstr "vis nøkkelgrep"
 
 msgid "list key and user IDs"
-msgstr "liste nøkler og brukerider"
+msgstr "vis nøkler og bruker-id-er"
 
 msgid "select user ID N"
-msgstr "velger brukerid N"
+msgstr "velger bruker-ID N"
 
 msgid "select subkey N"
-msgstr "velger brukerid N"
+msgstr "velger bruker-ID N"
 
 msgid "check signatures"
 msgstr "sjekke signaturer"
 
 msgid "sign selected user IDs [* see below for related commands]"
-msgstr ""
+msgstr "signer valgte bruker-id-er [* se nedenfor for relevante kommandoer]"
 
 msgid "sign selected user IDs locally"
-msgstr "signerere utvalgte brukerider lokalt"
+msgstr "signerer valgte bruker-id-er lokalt"
 
 msgid "sign selected user IDs with a trust signature"
-msgstr "signere utvalgte brukerider med en tillitssignatur"
+msgstr "signer valgte bruker-id-er med tillitssignatur"
 
 msgid "sign selected user IDs with a non-revocable signature"
 msgstr ""
+"signer valgte bruker-id-er med en signatur som ikke kan trekkes tilbake"
 
 msgid "add a user ID"
-msgstr "legge til en brukerid"
+msgstr "legg til bruker-ID"
 
 msgid "add a photo ID"
-msgstr "legge til en fotoid"
+msgstr "legg til foto-ID"
 
 msgid "delete selected user IDs"
-msgstr "slette utvalgte brukerider"
+msgstr "slett valgte bruker-id-er"
 
 msgid "add a subkey"
-msgstr "legge til en undernøkkel"
+msgstr "legg til undernøkkel"
 
 msgid "add a key to a smartcard"
-msgstr ""
+msgstr "legg til nøkkel på et smartkort"
 
 msgid "move a key to a smartcard"
-msgstr ""
+msgstr "flytt nøkkel til et smartkort"
 
 msgid "move a backup key to a smartcard"
-msgstr ""
+msgstr "flytt en sikkerhetskopi-nøkkel til et smartkort"
 
 msgid "delete selected subkeys"
-msgstr "slette utvalgte undernøkler"
+msgstr "slett valgte undernøkler"
 
 msgid "add a revocation key"
-msgstr "legge til en opphevingsnøkkel"
+msgstr "legg til opphevingsnøkkel"
 
 msgid "delete signatures from the selected user IDs"
-msgstr "slette signaturene fra de utvalgte brukeridene"
+msgstr "slett signaturer fra valgte bruker-id-er"
 
 msgid "change the expiration date for the key or selected subkeys"
-msgstr ""
+msgstr "endre utløpsdato for nøkkelen eller valgte undernøkler"
 
 msgid "flag the selected user ID as primary"
-msgstr "markere den valgte brukeriden som den primære"
+msgstr "marker valgt bruker-ID som primær"
 
 msgid "list preferences (expert)"
-msgstr "liste preferanser (ekspert)"
+msgstr "vis innstillinger (avansert)"
 
 msgid "list preferences (verbose)"
-msgstr "liste preferanser (fyldig)"
+msgstr "vis innstillinger (detaljert)"
 
 msgid "set preference list for the selected user IDs"
-msgstr "sette preferanseliste for de valgte brukeridene"
+msgstr "velg oppsettsliste for valgte bruker-id-er"
 
 msgid "set the preferred keyserver URL for the selected user IDs"
-msgstr "sette URL for foretrukket nøkkelserver for de valgte brukeridene"
+msgstr "endre adresse til foretrukket nøkkeltjener for valgte bruker-id-er"
 
 msgid "set a notation for the selected user IDs"
-msgstr "sette en notasjon for de valgte brukeridene"
+msgstr "endre notat for valgte bruker-id-er"
 
 msgid "change the passphrase"
-msgstr "endre passfrasen"
+msgstr "endre passordfrase"
 
 msgid "change the ownertrust"
-msgstr "endre eiertilliten"
+msgstr "endre eiertillit"
 
 msgid "revoke signatures on the selected user IDs"
-msgstr "oppheve signaturene på de valgte brukeridene"
+msgstr "opphev signaturer på valgte bruker-id-er"
 
 msgid "revoke selected user IDs"
-msgstr "oppheve utvalgte brukerider"
+msgstr "opphev valgte bruker-id-er"
 
 msgid "revoke key or selected subkeys"
-msgstr "oppheve nøkkel eller utvalgte undernøkler"
+msgstr "opphev nøkkel eller valgte undernøkler"
 
 msgid "enable key"
-msgstr "innkoble en nøkkel"
+msgstr "ta nøkkel i bruk"
 
 msgid "disable key"
-msgstr "utkoble en nøkkel"
+msgstr "ta nøkkel ut av bruk"
 
 msgid "show selected photo IDs"
-msgstr "vise utvalgte fotoider"
+msgstr "vis valgte foto-id-er"
 
 msgid "compact unusable user IDs and remove unusable signatures from key"
 msgstr ""
+"pakkk sammen ubrukelige bruker-id-er og fjern ubrukelige signaturer fra "
+"nøkkel"
 
 msgid "compact unusable user IDs and remove all signatures from key"
 msgstr ""
+"pakkk sammen ubrukelige bruker-id-er og fjern alle signaturer fra nøkkel"
 
 msgid "Secret key is available.\n"
-msgstr "Hemmelig nøkkel er tilgjengelig\n"
+msgstr "Hemmelig nøkkel er tilgjengelig.\n"
 
 msgid "Need the secret key to do this.\n"
-msgstr "Trenger den hemmelige nøkkelen for å gjøre dette.\n"
+msgstr "Du trenger tilhørende hemmelig nøkkel for å gjøre dette.\n"
 
 msgid ""
 "* The 'sign' command may be prefixed with an 'l' for local signatures "
@@ -3340,165 +3201,167 @@ msgid ""
 "  a 't' for trust signatures (tsign), an 'nr' for non-revocable signatures\n"
 "  (nrsign), or any combination thereof (ltsign, tnrsign, etc.).\n"
 msgstr ""
+"* Kommandoen «sign» kan brukes med prefiks «l» for lokale signaturer "
+"(lsign),\n"
+"  «t» for tillitssignaturer (tsign), «nr» for signaturer som ikke kan "
+"oppheves\n"
+"  (nrsign), eller hvilken som helst kombinasjon av disse (ltsign, tnrsign, "
+"osv.).\n"
 
 msgid "Key is revoked."
-msgstr "Nøkkelen er opphevet."
+msgstr "Nøkkelen er opphevet."
 
 msgid "Really sign all user IDs? (y/N) "
-msgstr "Virkelig signerere alle brukerider? (j/N) "
+msgstr "Er du sikekr på at du vil signerere alle bruker-id-er? (j/N) "
 
-#, fuzzy
-#| msgid "Really sign all user IDs? (y/N) "
 msgid "Really sign all text user IDs? (y/N) "
-msgstr "Virkelig signerere alle brukerider? (j/N) "
+msgstr "Er du sikker på at du vil signerere alle bruker-id-er? (j/N) "
 
 msgid "Hint: Select the user IDs to sign\n"
-msgstr "Tips: Velg brukeriden som skal signeres\n"
+msgstr "Tips: Velg bruker-id-en(e) du vil signere\n"
 
-#, fuzzy, c-format
-#| msgid "Unknown signature type `%s'\n"
+#, c-format
 msgid "Unknown signature type '%s'\n"
-msgstr "Ukjent signaturtype «%s»\n"
+msgstr "«%s» er en ukjent signaturtype\n"
 
 #, c-format
 msgid "This command is not allowed while in %s mode.\n"
 msgstr "Denne kommandoen er ikke tillatt i %s-modus.\n"
 
 msgid "You must select at least one user ID.\n"
-msgstr "Du må velge minst en brukerid.\n"
+msgstr "Du må velge minst én bruker-ID.\n"
 
 #, c-format
 msgid "(Use the '%s' command.)\n"
-msgstr ""
+msgstr "(Bruk kommandoen «%s».)\n"
 
 msgid "You can't delete the last user ID!\n"
-msgstr "Du kan ikke slette den siste brukeriden!\n"
+msgstr "Du kan ikke slette siste bruker-ID.\n"
 
 msgid "Really remove all selected user IDs? (y/N) "
-msgstr "Virkelig fjerne alle valgte brukerider? (j/N) "
+msgstr "Er du sikker på at du vil fjerne alle valgte bruker-id-er? (j/N) "
 
 msgid "Really remove this user ID? (y/N) "
-msgstr "Virkelig fjerne denne brukeriden? (j/N) "
+msgstr "Er du sikker på at du vil fjerne valgt bruker-ID? (j/N) "
 
 #. TRANSLATORS: Please take care: This is about
 #. moving the key and not about removing it.
 msgid "Really move the primary key? (y/N) "
-msgstr "Virkelig flytte primærnøkkelen? (j/N) "
+msgstr "Er du sikker på at du vil flytte primærnøkkelen? (j/N) "
 
 msgid "You must select exactly one key.\n"
-msgstr "Du må velge minst en nøkkel.\n"
+msgstr "Du må velge minst én nøkkel.\n"
 
 msgid "Command expects a filename argument\n"
-msgstr ""
+msgstr "Kommandoen forventer et filnavn-argument\n"
 
-#, fuzzy, c-format
-#| msgid "Can't open `%s': %s\n"
+#, c-format
 msgid "Can't open '%s': %s\n"
-msgstr "Kan ikke åpne «%s»: %s\n"
+msgstr "Klarte ikke Ã¥ Ã¥pne Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "Error reading backup key from `%s': %s\n"
+#, c-format
 msgid "Error reading backup key from '%s': %s\n"
-msgstr "Feil ved lesing av sikkerhetskopiert nøkkel «%s»: %s\n"
+msgstr "Feil under lesing av sikkerhetskopi-nøkkel fra Â«%s»: %s\n"
 
 msgid "You must select at least one key.\n"
-msgstr "Du må velge minst en nøkkel.\n"
+msgstr "Du må velge minst én nøkkel.\n"
 
 msgid "Do you really want to delete the selected keys? (y/N) "
-msgstr "Vil du virkelig slette den valgte nøkkelen? (j/N) "
+msgstr "Er du sikker på at du vil slette valgt nøkkel? (j/N) "
 
 msgid "Do you really want to delete this key? (y/N) "
-msgstr "Vil du virkelig slette denne nøkkelen? (j/N) "
+msgstr "Er du sikker på at du vil slette denne nøkkelen? (j/N) "
 
 msgid "Really revoke all selected user IDs? (y/N) "
-msgstr "Virkelig oppheve alle de valgte brukeridene? (j/N) "
+msgstr "Er du sikker på at du vil oppheve alle valgte bruker-id-er? (j/N) "
 
 msgid "Really revoke this user ID? (y/N) "
-msgstr "Virkelig oppheve denne brukeriden? (j/N) "
+msgstr "Er du sikker på at du vil oppheve denne bruker-id-en? (j/N) "
 
 msgid "Do you really want to revoke the entire key? (y/N) "
-msgstr "Vil du virkelig oppheve hele nøkkelen? (j/N) "
+msgstr "Er du sikker på at du vil oppheve hele nøkkelen? (j/N) "
 
 msgid "Do you really want to revoke the selected subkeys? (y/N) "
-msgstr "Vil du virkelig oppheve de valgte undernøklene? (j/N) "
+msgstr "Er du sikker på at du vil oppheve valgte undernøkler? (j/N) "
 
 msgid "Do you really want to revoke this subkey? (y/N) "
-msgstr "Vil du virkelig oppheve denne undernøkkelen? (j/N) "
+msgstr "Er du sikker på at du vil oppheve denne undernøkkelen? (j/N) "
 
 msgid "Owner trust may not be set while using a user provided trust database\n"
 msgstr ""
+"Du kan ikke justere eiertillit når du bruker selvvalgt tillitsdatabase\n"
 
 msgid "Set preference list to:\n"
-msgstr "sette preferanseliste til:\n"
+msgstr "Bytt oppsettsliste til:\n"
 
 msgid "Really update the preferences for the selected user IDs? (y/N) "
-msgstr "Virkelig oppdatere preferansene for de valgte brukeridene? (j/N) "
+msgstr ""
+"Er du sikker på at du vil oppdatere oppsett for valgte bruker-id-er? (j/N) "
 
 msgid "Really update the preferences? (y/N) "
-msgstr "Virkelig oppdatere preferansene? (j/N) "
+msgstr "Er du sikker på at du vil oppdatere oppsett? (j/N) "
 
 msgid "Save changes? (y/N) "
-msgstr "Lagre endringene? (j/N) "
+msgstr "Vil du lagre endringer? (j/N) "
 
 msgid "Quit without saving? (y/N) "
-msgstr "Avslutte uten å lagre? (j/N) "
+msgstr "Vil du avslutte uten å lagre? (j/N) "
 
 #, c-format
 msgid "update failed: %s\n"
 msgstr "oppdatering mislyktes: %s\n"
 
 msgid "Key not changed so no update needed.\n"
-msgstr "Nøkkelen ble ikke endret, så ingen oppdatering er nødvendig.\n"
+msgstr "Nøkkelen ble ikke endret, så ingen oppdatering er nødvendig.\n"
 
 #, fuzzy, c-format
-#| msgid "invalid fingerprint"
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Nøkkelgenerering mislyktes: %s\n"
+
+#, c-format
 msgid "\"%s\" is not a fingerprint\n"
-msgstr "ugyldig fingeravtrykk"
+msgstr "«%s» er ikke et fingeravtrykk\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "\"%s\" is not the primary fingerprint\n"
-msgstr "klarte ikke å lagre fingeravtrykket: %s\n"
+msgstr "«%s» er ikke primært fingeravtrykk\n"
 
-#, fuzzy, c-format
-#| msgid "invalid value\n"
+#, c-format
 msgid "Invalid user ID '%s': %s\n"
-msgstr "ugyldig verdi\n"
+msgstr "Bruker-ID «%s» er ugyldig: %s\n"
 
-#, fuzzy
-#| msgid "No such user ID.\n"
 msgid "No matching user IDs."
-msgstr "Det finnes ingen slik brukerid.\n"
+msgstr "Ingen treff på bruker-id-er."
 
-#, fuzzy
-#| msgid "Nothing to sign with key %s\n"
 msgid "Nothing to sign.\n"
-msgstr "Ingenting å signere med nøkkelen %s\n"
+msgstr "Ingenting å signere.\n"
 
 msgid "Digest: "
-msgstr "Digest: "
+msgstr "Kontrollsum: "
 
 msgid "Features: "
-msgstr "Særtrekk: "
+msgstr "Funksjoner: "
 
 msgid "Keyserver no-modify"
-msgstr ""
+msgstr "Nøkkeltjener no-modify"
 
 msgid "Preferred keyserver: "
-msgstr ""
+msgstr "Foretrukket nøkkeltjener: "
 
 msgid "Notations: "
 msgstr "Notasjoner: "
 
 msgid "There are no preferences on a PGP 2.x-style user ID.\n"
-msgstr "Det er ingen preferanser for en PGP 2.x-aktig brukerid.\n"
+msgstr "PGP 2.x-brukere har ingen oppsettsmuligheter.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "The following key was revoked on %s by %s key %s\n"
-msgstr "Denne nøkkelen ble opphevet den %s av %s med nøkkelen %s\n"
+msgstr "Følgende nøkkel ble opphevet %s av %s med nøkkelen %s\n"
 
 #, c-format
 msgid "This key may be revoked by %s key %s"
-msgstr "Denne nøkkelen kan bli opphevet av %s med nøkkelen %s"
+msgstr "Denne nøkkelen kan bli opphevet av %s med nøkkelen %s"
 
 msgid "(sensitive)"
 msgstr "(sensitiv)"
@@ -3517,14 +3380,14 @@ msgstr "utgikk: %s"
 
 #, c-format
 msgid "expires: %s"
-msgstr "utgår: %s"
+msgstr "utgår: %s"
 
 #, c-format
 msgid "usage: %s"
-msgstr "bruksmåte: %s"
+msgstr "bruk: %s"
 
 msgid "card-no: "
-msgstr ""
+msgstr "kortnr.: "
 
 #, c-format
 msgid "trust: %s"
@@ -3535,63 +3398,69 @@ msgid "validity: %s"
 msgstr "gyldighet: %s"
 
 msgid "This key has been disabled"
-msgstr "Denne nøkkelen har blitt utkoblet"
+msgstr "Denne nøkkelen er ikke i bruk"
 
 msgid ""
 "Please note that the shown key validity is not necessarily correct\n"
 "unless you restart the program.\n"
 msgstr ""
+"Merk: du bør starte programmet på nytt for å sikre at nøkkel-gyldigheten\n"
+"som vises her er riktig.\n"
 
 msgid "revoked"
 msgstr "opphevet"
 
 msgid "expired"
-msgstr "utgått"
+msgstr "utgått"
 
 msgid ""
 "WARNING: no user ID has been marked as primary.  This command may\n"
 "              cause a different user ID to become the assumed primary.\n"
 msgstr ""
+"ADVARSEL: ingen bruker-ID er merket som primær. Denne kommandoen kan\n"
+"              føre til at en annen bruker-ID blir brukt som primærbruker.\n"
 
 msgid "WARNING: Your encryption subkey expires soon.\n"
-msgstr ""
+msgstr "ADVARSEL: Undernøkkel for kryptering utløper snart.\n"
 
 msgid "You may want to change its expiration date too.\n"
-msgstr ""
+msgstr "Du bør vurdere å endre utløpsdato samtidig.\n"
 
 msgid ""
 "WARNING: This is a PGP2-style key.  Adding a photo ID may cause some "
 "versions\n"
 "         of PGP to reject this key.\n"
 msgstr ""
+"ADVARSEL: Dette er en PGP2-nøkkel. Hvis du legger til et foto-ID, kan det "
+"føre til at\n"
+"         enkelte PGP-versjoner avviser nøkkelen.\n"
 
 msgid "Are you sure you still want to add it? (y/N) "
-msgstr "Er du sikker på at du vil legge den til? (j/N) "
+msgstr "Er du sikker på at du vil legge den til? (j/N) "
 
 msgid "You may not add a photo ID to a PGP2-style key.\n"
-msgstr ""
+msgstr "Du kan ikke knytte foto-ID til PGP2-nøkler.\n"
 
 msgid "Such a user ID already exists on this key!\n"
-msgstr ""
+msgstr "Valgt bruker-ID finnes allerede på denne nøkkelen!\n"
 
 msgid "Delete this good signature? (y/N/q)"
 msgstr "Slette denne gode signaturen? (j/N/a)"
 
 msgid "Delete this invalid signature? (y/N/q)"
-msgstr ""
+msgstr "Vil du slette denne ugyldige signaturen? (j/N/q)"
 
 msgid "Delete this unknown signature? (y/N/q)"
-msgstr ""
+msgstr "Vil du slette denne ukjente signaturen? (j/N/q)"
 
 msgid "Really delete this self-signature? (y/N)"
-msgstr ""
+msgstr "Er du sikker på at du vil slette denne selvsignaturen? (j/N)"
 
-#, fuzzy, c-format
-#| msgid "Deleted %d signature.\n"
+#, c-format
 msgid "Deleted %d signature.\n"
 msgid_plural "Deleted %d signatures.\n"
 msgstr[0] "Slettet %d signatur.\n"
-msgstr[1] "Slettet %d signatur.\n"
+msgstr[1] "Slettet %d signaturer.\n"
 
 msgid "Nothing deleted.\n"
 msgstr "Ingen ble slettet.\n"
@@ -3599,202 +3468,202 @@ msgstr "Ingen ble slettet.\n"
 msgid "invalid"
 msgstr "ugyldig"
 
-#, fuzzy, c-format
+#, c-format
 msgid "User ID \"%s\" compacted: %s\n"
-msgstr "brukerid «%s»: allerede renset\n"
+msgstr "Bruker-ID «%s» pakket sammen: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "User ID \"%s\": %d signature removed\n"
 msgid_plural "User ID \"%s\": %d signatures removed\n"
-msgstr[0] "nøkkel: %s: «%s» %d nye signaturer\n"
-msgstr[1] "nøkkel: %s: «%s» %d nye signaturer\n"
+msgstr[0] "Bruker-ID «%s»: %d signatur fjernet\n"
+msgstr[1] "Bruker-ID «%s»: %d signaturer fjernet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "User ID \"%s\": already minimized\n"
-msgstr "brukerid «%s»: allerede renset\n"
+msgstr "Bruker-ID «%s»: allerede minimert\n"
 
 #, c-format
 msgid "User ID \"%s\": already clean\n"
-msgstr "brukerid «%s»: allerede renset\n"
+msgstr "Bruker-ID Â«%s»: allerede renset\n"
 
 msgid ""
 "WARNING: This is a PGP 2.x-style key.  Adding a designated revoker may "
 "cause\n"
 "         some versions of PGP to reject this key.\n"
 msgstr ""
+"ADVARSEL: Dette er en PGP 2.x-nøkkel. Hvis du legger til en opphever,\n"
+"         kan dette føre til at enkelte PGP-versjoner ikke vil kunne bruke "
+"nøkkelen.\n"
 
 msgid "You may not add a designated revoker to a PGP 2.x-style key.\n"
-msgstr ""
+msgstr "Du kan ikke knytte opphevere til PGP 2.x-nøkler.\n"
 
 msgid "Enter the user ID of the designated revoker: "
-msgstr ""
+msgstr "Skriv inn oppheverens bruker-ID: "
 
 msgid "cannot appoint a PGP 2.x style key as a designated revoker\n"
-msgstr ""
+msgstr "du kan ikke bruke PGP 2.x-nøkler som opphevere\n"
 
 msgid "you cannot appoint a key as its own designated revoker\n"
-msgstr ""
+msgstr "du kan ikke bruke en nøkkel som opphevelsesnøkkel for seg selv\n"
 
 msgid "this key has already been designated as a revoker\n"
-msgstr ""
+msgstr "denne nøkkelen er allerede i bruk som opphevelsesnøkkel\n"
 
 msgid "WARNING: appointing a key as a designated revoker cannot be undone!\n"
 msgstr ""
+"ADVARSEL: du kan ikke angre tildeling av opphevelsesrolle til en nøkkel.\n"
 
 msgid ""
 "Are you sure you want to appoint this key as a designated revoker? (y/N) "
-msgstr ""
-"Er du fortsatt sikker på at du vil gjøre denne nøkkelen til en opphever? (j/"
-"N) "
+msgstr "Er du sikker på at du vil gjøre denne nøkkelen til en opphever? (j/N) "
 
-#, fuzzy
-#| msgid ""
-#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgid ""
 "Are you sure you want to change the expiration time for multiple subkeys? (y/"
 "N) "
 msgstr ""
-"Er du fortsatt sikker på at du vil gjøre denne nøkkelen til en opphever? (j/"
-"N) "
+"Er du sikker på at du vil endre utløpstid for flere undernøkler? (j/N) "
 
 msgid "Changing expiration time for a subkey.\n"
-msgstr ""
+msgstr "Endrer utløpstid for undernøkkel.\n"
 
 msgid "Changing expiration time for the primary key.\n"
-msgstr ""
+msgstr "Endrer utløpstid for primærnøkkel.\n"
 
 msgid "You can't change the expiration date of a v3 key\n"
-msgstr ""
+msgstr "Du kan ikke endre utløpsdato for v3-nøkler\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "signing subkey %s is already cross-certified\n"
-msgstr "Undernøkkel %s er allerede opphevet.\n"
+msgstr "signerings-undernøkkel %s er allerede kryssertifisert\n"
 
 #, c-format
 msgid "subkey %s does not sign and so does not need to be cross-certified\n"
 msgstr ""
+"undernøkkel %s signerer ikke, og behøver derfor ikke å bli kryssertifisert\n"
 
 msgid "Please select exactly one user ID.\n"
-msgstr ""
+msgstr "Velg én bruker-ID.\n"
 
 #, c-format
 msgid "skipping v3 self-signature on user ID \"%s\"\n"
-msgstr "hopper over v3 selvsignatur for brukerid «%s»\n"
+msgstr "hopper over v3-selvsignatur for bruker-ID Â«%s»\n"
 
 msgid "Enter your preferred keyserver URL: "
-msgstr ""
+msgstr "Skriv inn adresse til foretrukket nøkkeltjener: "
 
 msgid "Are you sure you want to replace it? (y/N) "
-msgstr "Er du sikker på at du vil erstatte den? (j/N) "
+msgstr "Er du sikker på at du vil erstatte den? (j/N) "
 
 msgid "Are you sure you want to delete it? (y/N) "
-msgstr "Er du sikker på at du vil slette den? (j/N) "
+msgstr "Er du sikker på at du vil slette den? (j/N) "
 
 msgid "Enter the notation: "
-msgstr ""
+msgstr "Skriv inn notat: "
 
 msgid "Proceed? (y/N) "
-msgstr ""
+msgstr "Vil du fortsette? (j/N) "
 
 #, c-format
 msgid "No user ID with index %d\n"
-msgstr ""
+msgstr "Ingen bruker-ID med indeks %d\n"
 
 #, c-format
 msgid "No user ID with hash %s\n"
-msgstr ""
+msgstr "Ingen bruker-ID med kontrollsum %s\n"
 
-#, fuzzy, c-format
-#| msgid "Nothing to sign with key %s\n"
+#, c-format
 msgid "No subkey with key ID '%s'.\n"
-msgstr "Ingenting å signere med nøkkelen %s\n"
+msgstr "Ingen undernøkkel med ID «%s».\n"
 
 #, c-format
 msgid "No subkey with index %d\n"
-msgstr ""
+msgstr "Ingen undernøkkel med indeks %d\n"
 
 #, c-format
 msgid "user ID: \"%s\"\n"
-msgstr ""
+msgstr "bruker-ID: «%s»\n"
 
 #, c-format
 msgid "signed by your key %s on %s%s%s\n"
-msgstr ""
+msgstr "signert med nøkkelen %s %s%s%s\n"
 
 msgid " (non-exportable)"
 msgstr " (ikke-eksporterbar)"
 
 #, c-format
 msgid "This signature expired on %s.\n"
-msgstr "Denne signaturen utgikk den %s.\n"
+msgstr "Denne signaturen utgikk %s.\n"
 
 msgid "Are you sure you still want to revoke it? (y/N) "
-msgstr ""
+msgstr "Er du sikker på at du vil oppheve den? (j/N) "
 
 msgid "Create a revocation certificate for this signature? (y/N) "
-msgstr ""
+msgstr "Vil du lage et opphevelsessertifikat for denne signaturen? (j/N) "
 
 msgid "Not signed by you.\n"
-msgstr ""
+msgstr "Ikke signert av deg.\n"
 
 #, c-format
 msgid "You have signed these user IDs on key %s:\n"
-msgstr ""
+msgstr "Du har signert disse bruker-id-ene med nøkkelen %s:\n"
 
 msgid " (non-revocable)"
-msgstr " (ikke-opphevbar)"
+msgstr " (kan ikke oppheves)"
 
 #, c-format
 msgid "revoked by your key %s on %s\n"
-msgstr ""
+msgstr "opphevet med nøkkelen %s %s\n"
 
 msgid "You are about to revoke these signatures:\n"
-msgstr ""
+msgstr "Du er i ferd med å oppheve følgende signaturer:\n"
 
 msgid "Really create the revocation certificates? (y/N) "
-msgstr ""
+msgstr "Er du sikker på at du vil lage opphevelsessertifikatene? (j/N) "
 
 msgid "no secret key\n"
-msgstr "ingen hemmelig nøkkel\n"
+msgstr "ingen hemmelig nøkkel\n"
+
+#, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
 
 #, c-format
 msgid "user ID \"%s\" is already revoked\n"
-msgstr "brukerid «%s» er allerede opphevet\n"
+msgstr "bruker-ID Â«%s» er allerede opphevet\n"
 
 #, c-format
 msgid "WARNING: a user ID signature is dated %d seconds in the future\n"
-msgstr "ADVARSEL: en brukeridsignatur er datert %d sekunder i fremtiden\n"
+msgstr "ADVARSEL: en bruker-id-signatur er datert %d sekunder i fremtiden\n"
 
 #, c-format
 msgid "Key %s is already revoked.\n"
-msgstr "Nøkkelen %s er allerede opphevet.\n"
+msgstr "Nøkkelen %s er allerede opphevet.\n"
 
 #, c-format
 msgid "Subkey %s is already revoked.\n"
-msgstr "Undernøkkel %s er allerede opphevet.\n"
+msgstr "Undernøkkel %s er allerede opphevet.\n"
 
 #, c-format
 msgid "Displaying %s photo ID of size %ld for key %s (uid %d)\n"
-msgstr ""
+msgstr "Viser %s foto-ID av størrelsen %ld for nøkkel %s (uid %d)\n"
 
-#, fuzzy, c-format
-#| msgid "preference `%s' duplicated\n"
+#, c-format
 msgid "preference '%s' duplicated\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "innstilling «%s» er duplisert\n"
 
 msgid "too many cipher preferences\n"
-msgstr "for mange cipher-preferanser\n"
+msgstr "for mange krypteringsinnstillinger\n"
 
 msgid "too many digest preferences\n"
-msgstr "for mange digest-preferanser\n"
+msgstr "for mange kontrollsum-innstillinger\n"
 
 msgid "too many compression preferences\n"
-msgstr "for mange kompresjons-preferanser\n"
+msgstr "for mange komprimeringsinnstillinger\n"
 
-#, fuzzy, c-format
-#| msgid "invalid item `%s' in preference string\n"
+#, c-format
 msgid "invalid item '%s' in preference string\n"
-msgstr "ugyldig oppføring «%s» i preferansestreng\n"
+msgstr "«%s» er et ugyldig oppsettsvalg\n"
 
 msgid "writing direct signature\n"
 msgstr "skriver direkte signatur\n"
@@ -3803,19 +3672,21 @@ msgid "writing self signature\n"
 msgstr "skriver selvsignatur\n"
 
 msgid "writing key binding signature\n"
-msgstr "skriver nøkkelbindende signatur\n"
+msgstr "skriver nøkkelbindende signatur\n"
 
 #, c-format
 msgid "keysize invalid; using %u bits\n"
-msgstr "nøkkelstørrelsen er ugyldig; bruker %u bits\n"
+msgstr "ugyldig nøkkelstørrelse. Bruker %u bit\n"
 
 #, c-format
 msgid "keysize rounded up to %u bits\n"
-msgstr "nøkkelstørrelsen ble rundet opp til %u bits\n"
+msgstr "nøkkelstørrelse rundet opp til %u bit\n"
 
 msgid ""
 "WARNING: some OpenPGP programs can't handle a DSA key with this digest size\n"
 msgstr ""
+"ADVARSEL: noen OpenPGP-programmer klarer ikke å behandle DSA-nøkler med "
+"denne kontrollsum-størrelsen\n"
 
 msgid "Sign"
 msgstr "Signere"
@@ -3848,37 +3719,37 @@ msgstr "SsKkAaQq"
 
 #, c-format
 msgid "Possible actions for a %s key: "
-msgstr ""
+msgstr "Mulige handlinger med en %s-nøkkel: "
 
 msgid "Current allowed actions: "
-msgstr ""
+msgstr "Tillatte handlinger: "
 
 #, c-format
 msgid "   (%c) Toggle the sign capability\n"
-msgstr ""
+msgstr "   (%c) Slå av/på signeringsfunksjon\n"
 
 #, c-format
 msgid "   (%c) Toggle the encrypt capability\n"
-msgstr ""
+msgstr "   (%c) Slå av/på krypteringsfunksjon\n"
 
 #, c-format
 msgid "   (%c) Toggle the authenticate capability\n"
-msgstr ""
+msgstr "   (%c) Slå av/på autentiseringsfunksjon\n"
 
 #, c-format
 msgid "   (%c) Finished\n"
-msgstr ""
+msgstr "   (%c) Ferdig\n"
 
 msgid "Please select what kind of key you want:\n"
-msgstr "Vennligst velg hvilken type nøkkel du vil ha:\n"
+msgstr "Velg hvilken type nøkkel du vil ha:\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) RSA and RSA (default)\n"
-msgstr "   (%d) DSA og ElGamal (standard)\n"
+msgstr "   (%d) RSA og RSA (standard)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) DSA and Elgamal\n"
-msgstr "   (%d) DSA og ElGamal (standard)\n"
+msgstr "   (%d) DSA og Elgamal\n"
 
 #, c-format
 msgid "   (%d) DSA (sign only)\n"
@@ -3904,63 +3775,57 @@ msgstr "   (%d) DSA (sette dine egne muligheter)\n"
 msgid "   (%d) RSA (set your own capabilities)\n"
 msgstr "   (%d) RSA (sette dine egne muligheter)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) ECC and ECC\n"
-msgstr "   (%d) DSA og ElGamal (standard)\n"
+msgstr "   (%d) ECC og ECC\n"
 
-#, fuzzy, c-format
-#| msgid "   (%d) DSA (sign only)\n"
+#, c-format
 msgid "  (%d) ECC (sign only)\n"
-msgstr "   (%d) DSA (bare signering)\n"
+msgstr "  (%d) ECC (kun signering)\n"
 
-#, fuzzy, c-format
-#| msgid "   (%d) DSA (set your own capabilities)\n"
+#, c-format
 msgid "  (%d) ECC (set your own capabilities)\n"
-msgstr "   (%d) DSA (sette dine egne muligheter)\n"
+msgstr "  (%d) ECC (velg funksjoner selv)\n"
 
-#, fuzzy, c-format
-#| msgid "   (%d) RSA (encrypt only)\n"
+#, c-format
 msgid "  (%d) ECC (encrypt only)\n"
-msgstr "   (%d) RSA (bare kryptering)\n"
+msgstr "  (%d) ECC (kun kryptering)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "  (%d) Existing key\n"
-msgstr "   (2) Krypteringsnøkkel\n"
+msgstr "  (%d) Nøkkel\n"
 
 msgid "Enter the keygrip: "
-msgstr ""
+msgstr "Skriv inn nøkkelgrep: "
 
 msgid "Not a valid keygrip (expecting 40 hex digits)\n"
-msgstr ""
+msgstr "Ugyldig nøkkelgrep (forventer 40 heks-sifre)\n"
 
 msgid "No key with this keygrip\n"
-msgstr ""
+msgstr "Ingen nøkkel med dette nøkkelgrepet\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
+#, c-format
 msgid "rounded to %u bits\n"
-msgstr "rundet opp til %u bits\n"
+msgstr "rundet av til %u bit\n"
 
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
-msgstr ""
+msgstr "%s-nøkler må være mellom %u og %u bit lange.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "What keysize do you want for the subkey? (%u) "
-msgstr "Hvilken nøkkelstørrelse vil du ha? (%u) "
+msgstr "Hvor stor vil du at undernøkkelen skal være? (%u) "
 
 #, c-format
 msgid "What keysize do you want? (%u) "
-msgstr "Hvilken nøkkelstørrelse vil du ha? (%u) "
+msgstr "Hvor stor skal nøkkelen være? (%u) "
 
 #, c-format
 msgid "Requested keysize is %u bits\n"
-msgstr "Ønsket nøkkelstørrelse er %u bits\n"
+msgstr "Forespurt nøkkelstørrelse er %u bit\n"
 
-#, fuzzy
-#| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
-msgstr "Vennligst velg hvilken type nøkkel du vil ha:\n"
+msgstr "Velg elliptisk kurve:\n"
 
 msgid ""
 "Please specify how long the key should be valid.\n"
@@ -3970,12 +3835,12 @@ msgid ""
 "      <n>m = key expires in n months\n"
 "      <n>y = key expires in n years\n"
 msgstr ""
-"Vennligst angi hvor lenge nøkkelen skal være gyldig.\n"
-"         0 = nøkkelen utgår ikke\n"
-"      <n>  = nøkkelen utgår om n days\n"
-"      <n>w = nøkkelen utgår om n weeks\n"
-"      <n>m = nøkkelen utgår om n months\n"
-"      <n>y = nøkkelen utgår om n years\n"
+"Velg hvor lenge nøkkelen skal være gyldig.\n"
+"         0 = nøkkelen utgår ikke\n"
+"      <n>  = nøkkelen utgår om n days\n"
+"      <n>w = nøkkelen utgår om n weeks\n"
+"      <n>m = nøkkelen utgår om n months\n"
+"      <n>y = nøkkelen utgår om n years\n"
 
 msgid ""
 "Please specify how long the signature should be valid.\n"
@@ -3985,15 +3850,15 @@ msgid ""
 "      <n>m = signature expires in n months\n"
 "      <n>y = signature expires in n years\n"
 msgstr ""
-"Vennligst angi hvor lenge signaturen skal være gyldig.\n"
-"         0 = signaturen utgår ikke\n"
-"      <n>  = signaturen utgår om n days\n"
-"      <n>w = signaturen utgår om n weeks\n"
-"      <n>m = signaturen utgår om n months\n"
-"      <n>y = signaturen utgår om n years\n"
+"Velg hvor lenge signaturen skal være gyldig.\n"
+"         0 = signaturen utgår ikke\n"
+"      <n>  = signaturen utgår om n days\n"
+"      <n>w = signaturen utgår om n weeks\n"
+"      <n>m = signaturen utgår om n months\n"
+"      <n>y = signaturen utgår om n years\n"
 
 msgid "Key is valid for? (0) "
-msgstr "Nøkkelen er gyldig for? (0) "
+msgstr "Nøkkelen er gyldig for? (0) "
 
 #, c-format
 msgid "Signature is valid for? (%s) "
@@ -4003,25 +3868,25 @@ msgid "invalid value\n"
 msgstr "ugyldig verdi\n"
 
 msgid "Key does not expire at all\n"
-msgstr "Nøkkel utgår ikke i det hele tatt\n"
+msgstr "Nøkkel utgår ikke i det hele tatt\n"
 
 msgid "Signature does not expire at all\n"
-msgstr "Signaturen utgår ikke i det hele tatt\n"
+msgstr "Signaturen utgår ikke i det hele tatt\n"
 
 #, c-format
 msgid "Key expires at %s\n"
-msgstr "Nøkkel utgår den %s\n"
+msgstr "Nøkkel utgår %s\n"
 
 #, c-format
 msgid "Signature expires at %s\n"
-msgstr "Signaturen utgår den %s\n"
+msgstr "Signaturen utgår %s\n"
 
 msgid ""
 "Your system can't display dates beyond 2038.\n"
 "However, it will be correctly handled up to 2106.\n"
 msgstr ""
-"Systemet ditt kan ikke vise datoer etter 2038.\n"
-"Likevel vil det bli håndtert korrekt opp til 2106.\n"
+"Systemet ditt klarer ikke å håndtere datoer etter 2038.\n"
+"Likevel håndteres det korrekt frem til 2106.\n"
 
 msgid "Is this correct? (y/N) "
 msgstr "Er dette korrekt (j/N)? "
@@ -4031,6 +3896,9 @@ msgid ""
 "GnuPG needs to construct a user ID to identify your key.\n"
 "\n"
 msgstr ""
+"\n"
+"GnuPG må lage en bruker-ID for å identifisere nøkkelen.\n"
+"\n"
 
 #. TRANSLATORS: This string is in general not anymore used
 #. but you should keep your existing translation.  In case
@@ -4045,10 +3913,10 @@ msgid ""
 "\n"
 msgstr ""
 "\n"
-"Du trenger en brukerid for å identifisere nøkkelen din;\n"
-"programvaren konstruerer brukeriden ut fra fullt navn, kommentar og\n"
-"epostadresse til denne formen:\n"
-"    «Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>»\n"
+"Du trenger en bruker-ID for å identifisere nøkkelen din.\n"
+"Programmet lageren bruker-ID ut fra fullt navn, kommentar og\n"
+"e-postadresse, som f.keks. dette:\n"
+"    Â«Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>»\n"
 "\n"
 
 msgid "Real name: "
@@ -4059,19 +3927,19 @@ msgstr "Ugyldig tegn i navn\n"
 
 #, c-format
 msgid "The characters '%s' and '%s' may not appear in name\n"
-msgstr ""
+msgstr "Tegnene «%s» og «%s» kan ikke brukes i navn\n"
 
 msgid "Name may not start with a digit\n"
-msgstr "Navnet kan ikke starte med et siffer\n"
+msgstr "Navn kan ikke begynne med siffer\n"
 
 msgid "Name must be at least 5 characters long\n"
-msgstr "Navnet må være minst 5 tegn langt\n"
+msgstr "Navnet må bestå av minst 5 tegn\n"
 
 msgid "Email address: "
-msgstr "Epostadresse: "
+msgstr "E-postadresse: "
 
 msgid "Not a valid email address\n"
-msgstr "Ikke en gyldig epostadresse\n"
+msgstr "Ugyldig e-postadresse\n"
 
 msgid "Comment: "
 msgstr "Kommentar: "
@@ -4079,10 +3947,9 @@ msgstr "Kommentar: "
 msgid "Invalid character in comment\n"
 msgstr "Ugyldig tegn i kommentar\n"
 
-#, fuzzy, c-format
-#| msgid "You are using the `%s' character set.\n"
+#, c-format
 msgid "You are using the '%s' character set.\n"
-msgstr "Du bruker tegnsettet «%s».\n"
+msgstr "Du bruker tegnsettet Â«%s».\n"
 
 #, c-format
 msgid ""
@@ -4090,13 +3957,12 @@ msgid ""
 "    \"%s\"\n"
 "\n"
 msgstr ""
-"Du valgte denne brukeriden:\n"
-"    «%s»\n"
+"Du valgte denne bruker-id-en («USER-ID»):\n"
+"    Â«%s»\n"
 "\n"
 
 msgid "Please don't put the email address into the real name or the comment\n"
-msgstr ""
-"Vennligst ikke putt epostadressen inn i fullt navn eller i kommentaren\n"
+msgstr "Ikk bruk e-postadresse som navn eller kommentar\n"
 
 #. TRANSLATORS: These are the allowed answers in
 #. lower and uppercase.  Below you will find the matching
@@ -4118,18 +3984,14 @@ msgstr "Endre (N)avn, (K)ommentar, (E)postadresse eller (A)vslutt? "
 msgid "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "
 msgstr "Endre (N)avn, (K)ommentar, (E)postadresse eller (R)iktig/(A)vslutt? "
 
-#, fuzzy
-#| msgid "Change (N)ame, (C)omment, (E)mail or (Q)uit? "
 msgid "Change (N)ame, (E)mail, or (Q)uit? "
-msgstr "Endre (N)avn, (K)ommentar, (E)postadresse eller (A)vslutt? "
+msgstr "Endre (N)avn, (E)postadresse eller (A)vslutt? "
 
-#, fuzzy
-#| msgid "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "
 msgid "Change (N)ame, (E)mail, or (O)kay/(Q)uit? "
-msgstr "Endre (N)avn, (K)ommentar, (E)postadresse eller (R)iktig/(A)vslutt? "
+msgstr "Endre (N)avn, (E)postadresse eller (R)iktig/(A)vslutt? "
 
 msgid "Please correct the error first\n"
-msgstr "Vennligst korriger feilen først\n"
+msgstr "Rett opp feilen først\n"
 
 msgid ""
 "We need to generate a lot of random bytes. It is a good idea to perform\n"
@@ -4137,14 +3999,14 @@ msgid ""
 "disks) during the prime generation; this gives the random number\n"
 "generator a better chance to gain enough entropy.\n"
 msgstr ""
-"Vi trenger å generere ganske mange tilfeldige byter. Det er en god idé\n"
-"å utføre andre oppgaver (skrive på tastaturet, flytte på musa, la\n"
-"diskene jobbe) under primtallgenereringen; dette gir\n"
-"tilfeldig-tall-generatoren en bedre sjanse til å samle nok entropy.\n"
+"Vi må lage ganske mye vilkårlighetsdata. Du bør jobbe med\n"
+"andre ting (skrive på tastaturet, flytte på musa, la\n"
+"diskene jobbe) mens dette pågår. Da får\n"
+"tallgeneratoren bedre muligheter til å samle inn vilkårlighetsdata.\n"
 
 #, c-format
 msgid "Key generation failed: %s\n"
-msgstr "Nøkkelgenerering mislyktes: %s\n"
+msgstr "Nøkkelgenerering mislyktes: %s\n"
 
 #, c-format
 msgid ""
@@ -4152,372 +4014,354 @@ msgid ""
 "    \"%s\"\n"
 "\n"
 msgstr ""
+"Lager nøkkel for:\n"
+"    «%s»\n"
+"\n"
 
 msgid "Continue? (Y/n) "
-msgstr ""
+msgstr "Vil du fortsette? (J/n) "
 
-#, fuzzy, c-format
-#| msgid "key already exists\n"
+#, c-format
 msgid "A key for \"%s\" already exists\n"
-msgstr "nøkkel finnes allerede\n"
+msgstr "Det finnes allerede en nøkkel for «%s»\n"
 
-#, fuzzy
-#| msgid "Use this key anyway? (y/N) "
 msgid "Create anyway? (y/N) "
-msgstr "Bruke denne nøkkelen likevel? (j/N) "
+msgstr "Vil du lage nøkkel likevel? (j/N) "
 
-#, fuzzy
-#| msgid "generating new key\n"
 msgid "creating anyway\n"
-msgstr "generere en ny nøkkel\n"
+msgstr "lager likevel\n"
 
 #, c-format
 msgid "Note: Use \"%s %s\" for a full featured key generation dialog.\n"
 msgstr ""
+"Merk: Bruk «%s %s» for å se et fullverdig dialogvindu for nøkkelgenerering.\n"
 
 msgid "Key generation canceled.\n"
-msgstr "Nøkkelgenereringen ble avbrutt.\n"
+msgstr "Nøkkelgenerering ble avbrutt.\n"
 
-#, fuzzy, c-format
-#| msgid "can't create backup file `%s': %s\n"
+#, c-format
 msgid "can't create backup file '%s': %s\n"
-msgstr "kan ikke opprette sikkerhetskopifil «%s»: %s\n"
+msgstr "klarte ikke Ã¥ lage sikkerhetskopifila Â«%s»: %s\n"
 
 #, c-format
 msgid "Note: backup of card key saved to '%s'\n"
-msgstr ""
+msgstr "Merk: sikkerhetskopi av kortnøkkel lagret på «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "writing public key to `%s'\n"
+#, c-format
 msgid "writing public key to '%s'\n"
-msgstr "skriver offentlig nøkkel til «%s»\n"
+msgstr "skriver offentlig nøkkel til Â«%s»\n"
 
 #, c-format
 msgid "no writable public keyring found: %s\n"
-msgstr "ingen skrivbart offentlig nøkkelknippe ble funnet: %s\n"
+msgstr "fant ikke skrivbart offentlig nøkkelknippe. %s\n"
 
-#, fuzzy, c-format
-#| msgid "error writing public keyring `%s': %s\n"
+#, c-format
 msgid "error writing public keyring '%s': %s\n"
-msgstr "feil ved skriving av offentlig nøkkelknippe «%s»: %s\n"
+msgstr "feil under skriving av offentlig nøkkelknippe Â«%s»: %s\n"
 
 msgid "public and secret key created and signed.\n"
-msgstr "offentlig og hemmelig nøkkel opprettet og signert.\n"
+msgstr "offentlig og hemmelig nøkkel opprettet og signert.\n"
 
 msgid ""
 "Note that this key cannot be used for encryption.  You may want to use\n"
 "the command \"--edit-key\" to generate a subkey for this purpose.\n"
 msgstr ""
-"Merk at denne nøkkelen ikke kan brukes for kryptering.  Du ønsker\n"
-"kanskje å bruke kommandoen «--edit-key» for å generere en\n"
-"sekundærnøkkel for dette formålet.\n"
+"Merk at denne nøkkelen ikke kan brukes til kryptering. Du bør\n"
+"vurdere å bruke kommandoen «--edit-key» for å lage en\n"
+"undernøkkel til dette formålet.\n"
 
-# Er dette entallsformen av denne strengen?
 #, c-format
 msgid ""
 "key has been created %lu second in future (time warp or clock problem)\n"
 msgstr ""
-"nøkkel har blitt opprettet %lu sekund i fremtiden (time warp eller "
+"nøkkel har blitt opprettet %lu sekund i fremtiden (time warp- eller "
 "klokkeproblem)\n"
 
-# Er dette flertallsformen av denne og den forrige strengen?
 #, c-format
 msgid ""
 "key has been created %lu seconds in future (time warp or clock problem)\n"
 msgstr ""
-"nøkkel har blitt opprettet %lu sekunder i fremtiden (time warp eller "
+"nøkkel har blitt opprettet %lu sekunder i fremtiden (time warp- eller "
 "klokkeproblem)\n"
 
-#, fuzzy
-#| msgid "NOTE: creating subkeys for v3 keys is not OpenPGP compliant\n"
 msgid "Note: creating subkeys for v3 keys is not OpenPGP compliant\n"
 msgstr ""
-"MERK: opprettelse av undernøkler for v3-nøkler er ikke i samsvar med "
-"OpenPGP\n"
+"Merk: det strider med OpenPGP-standarden å lage undernøkler for v3-nøkler\n"
 
 msgid "Secret parts of primary key are not available.\n"
-msgstr "Hemmelige deler av primærnøkkelen er ikke tilgjengelig.\n"
+msgstr "Hemmelige deler av primærnøkkelen er ikke tilgjengelig.\n"
 
 msgid "Secret parts of primary key are stored on-card.\n"
-msgstr "Hemmelige deler av primærnøkkelen er lagret på kort.\n"
+msgstr "Hemmelige deler av primærnøkkelen er lagret på kort.\n"
 
 msgid "Really create? (y/N) "
-msgstr "Virkelig opprette? (j/N)"
+msgstr "Er du sikker på at du vil fortsette? (j/N) "
 
 msgid "never     "
-msgstr ""
+msgstr "aldri     "
 
 msgid "Critical signature policy: "
-msgstr ""
+msgstr "Regler for kritisk signatur: "
 
 msgid "Signature policy: "
-msgstr ""
+msgstr "Regler for signatur: "
 
 msgid "Critical preferred keyserver: "
-msgstr ""
+msgstr "Kritisk foretrukket nøkkeltjener: "
 
 msgid "Critical signature notation: "
-msgstr ""
+msgstr "Kritisk signaturnotat: "
 
 msgid "Signature notation: "
-msgstr ""
+msgstr "Signaturnotat: "
 
-#, fuzzy, c-format
-#| msgid "%d bad signatures\n"
+#, c-format
 msgid "%d good signature\n"
 msgid_plural "%d good signatures\n"
-msgstr[0] "%d ubrukelige signaturer\n"
-msgstr[1] "%d ubrukelige signaturer\n"
+msgstr[0] "%d gyldig signatur\n"
+msgstr[1] "%d gyldige signaturer\n"
 
-#, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
+#, c-format
 msgid "%d signature not checked due to an error\n"
 msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 signatur ble ikke sjekket på grunn av en feil\n"
-msgstr[1] "1 signatur ble ikke sjekket på grunn av en feil\n"
+msgstr[0] "%d signatur ble ikke kontrollert på grunn av feil\n"
+msgstr[1] "%d signaturer ble ikke kontrollert på grunn av feil\n"
 
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Advarsel: hoppet over %lu nøkkel pga. for høy størrelse\n"
+msgstr[1] "Advarsel: hoppet over %lu nøkler pga. for høy størrelse\n"
 
 msgid "Keyring"
-msgstr "Nøkkelknippe"
-
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "hoppet over «%s»: %s\n"
+msgstr "Nøkkelknippe"
 
 msgid "Primary key fingerprint:"
-msgstr "Fingeravtrykk for primærnøkkel:"
+msgstr "Fingeravtrykk for primærnøkkel:"
 
 msgid "     Subkey fingerprint:"
-msgstr "     Fingeravtrykk for undernøkkel:"
+msgstr "     Fingeravtrykk for undernøkkel:"
 
 #. TRANSLATORS: this should fit into 24 bytes so that the
 #. * fingerprint data is properly aligned with the user ID
 msgid " Primary key fingerprint:"
-msgstr " Fingeravtrykk for primærnøkkel:"
+msgstr " Fingeravtrykk for primærnøkkel:"
 
 msgid "      Subkey fingerprint:"
-msgstr "      Fingeravstrykk for undernøkkel:"
+msgstr "      Fingeravstrykk for undernøkkel:"
 
 msgid "      Key fingerprint ="
-msgstr " kkelfingeravtrykk ="
+msgstr "      Nøkkelfingeravtrykk ="
 
 msgid "      Card serial no. ="
 msgstr "      Serienummer for kort ="
 
-#, fuzzy, c-format
-#| msgid "caching keyring `%s'\n"
+#, c-format
 msgid "caching keyring '%s'\n"
-msgstr "cacher nøkkelknippet «%s»\n"
+msgstr "hurtiglagrer nøkkelknippe Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys cached so far (%lu signatures)\n"
+#, c-format
 msgid "%lu keys cached so far (%lu signature)\n"
 msgid_plural "%lu keys cached so far (%lu signatures)\n"
-msgstr[0] "%lu nøkler cachet så langt (%lu signaturer)\n"
-msgstr[1] "%lu nøkler cachet så langt (%lu signaturer)\n"
+msgstr[0] "%lu nøkler hurtiglagret så langt (%lu signatur)\n"
+msgstr[1] "%lu nøkler hurtiglagret så langt (%lu signaturer)\n"
 
 #, c-format
 msgid "%lu key cached"
 msgid_plural "%lu keys cached"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%lu nøkkel hurtiglagret"
+msgstr[1] "%lu nøkler hurtiglagret"
 
-#, fuzzy, c-format
-#| msgid "1 bad signature\n"
+#, c-format
 msgid " (%lu signature)\n"
 msgid_plural " (%lu signatures)\n"
-msgstr[0] "1 ubrukelig signatur\n"
-msgstr[1] "1 ubrukelig signatur\n"
+msgstr[0] " (%lu signatur)\n"
+msgstr[1] " (%lu signaturer)\n"
 
 #, c-format
 msgid "%s: keyring created\n"
-msgstr ""
+msgstr "%s: laget nøkkelknippe\n"
 
 msgid "override proxy options set for dirmngr"
-msgstr ""
+msgstr "overstyr mellomtjener-oppsett for dirmngr"
 
 msgid "include revoked keys in search results"
-msgstr ""
+msgstr "ta med opphevede nøkler som søketreff"
 
 msgid "include subkeys when searching by key ID"
-msgstr ""
+msgstr "ta med undernøkler ved søk på nøkkel-ID"
 
 msgid "override timeout options set for dirmngr"
-msgstr ""
+msgstr "overstyr tidsavbrudd-oppsett for dirmngr"
 
 msgid "automatically retrieve keys when verifying signatures"
-msgstr ""
+msgstr "hent nøkler automatisk ved bekreftelse av signaturer"
 
 msgid "honor the preferred keyserver URL set on the key"
-msgstr ""
+msgstr "bruk nøklers foretrukne nøkkeltjener-adresse"
 
 msgid "honor the PKA record set on a key when retrieving keys"
-msgstr ""
+msgstr "bruk nøklers PKA-oppføring når du henter dem"
 
 msgid "disabled"
-msgstr "utkoblet"
+msgstr "ikke i bruk"
 
 msgid "Enter number(s), N)ext, or Q)uit > "
-msgstr ""
+msgstr "Skriv inn tall, N)este, eller Q)uit (Avslutt) > "
 
 #, c-format
 msgid "invalid keyserver protocol (us %d!=handler %d)\n"
-msgstr ""
+msgstr "ugyldig nøkkeltjener-protokoll (us %d!=håndteringsprogram %d)\n"
 
 #, c-format
 msgid "\"%s\" not a key ID: skipping\n"
-msgstr ""
+msgstr "«%s» er ikke en nøkkel-ID, og blir hoppet over\n"
 
-#, fuzzy, c-format
-#| msgid "refreshing %d keys from %s\n"
+#, c-format
 msgid "refreshing %d key from %s\n"
 msgid_plural "refreshing %d keys from %s\n"
-msgstr[0] "oppfrisker %d nøkler fra %s\n"
-msgstr[1] "oppfrisker %d nøkler fra %s\n"
+msgstr[0] "oppdaterer %d nøkkel fra %s\n"
+msgstr[1] "oppdaterer %d nøkler fra %s\n"
 
 #, c-format
 msgid "WARNING: unable to refresh key %s via %s: %s\n"
-msgstr "ADVARSEL: klarte ikke å oppfriske nøkkel %s via %s: %s\n"
+msgstr "ADVARSEL: klarte ikke å oppdatere nøkkel %s via %s: %s\n"
 
 #, c-format
 msgid "key \"%s\" not found on keyserver\n"
-msgstr "nøkkelen «%s» ble ikke funnet på nøkkelserveren\n"
+msgstr "fant ikke nøkkelen «%s» på nøkkeltjener\n"
 
 msgid "key not found on keyserver\n"
-msgstr "nøkkelen ble ikke funnet på nøkkelserver\n"
+msgstr "fant ikke nøkkelen på nøkkeltjener\n"
 
 msgid "no keyserver known (use option --keyserver)\n"
-msgstr ""
+msgstr "ingen kjent nøkkeltjener (bruk valget «--keyserver»)\n"
 
 #, c-format
 msgid "requesting key %s from %s server %s\n"
-msgstr "ber om nøkkelen %s fra %s server %s\n"
+msgstr "ber om nøkkelen %s fra %s tjener %s\n"
 
 #, c-format
 msgid "requesting key %s from %s\n"
-msgstr "ber om nøkkel %s fra %s\n"
+msgstr "ber om nøkkelen %s fra %s\n"
 
-#, fuzzy
-#| msgid "no keyserver action!\n"
 msgid "no keyserver known\n"
-msgstr "ingen handling for nøkkelserver!\n"
+msgstr "ingen kjent nøkkeltjener\n"
+
+#, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "hoppet over «%s»: %s\n"
 
 #, c-format
 msgid "sending key %s to %s\n"
-msgstr ""
+msgstr "sender nøkkelen %s til %s\n"
 
-#, fuzzy, c-format
-#| msgid "requesting key %s from %s\n"
+#, c-format
 msgid "requesting key from '%s'\n"
-msgstr "ber om nøkkel %s fra %s\n"
+msgstr "ber om nøkkel fra «%s»\n"
 
 #, c-format
 msgid "WARNING: unable to fetch URI %s: %s\n"
-msgstr "ADVARSEL: klarte ikke å fange URI %s: %s\n"
+msgstr "ADVARSEL: klarte ikke å fange URI %s: %s\n"
 
 #, c-format
 msgid "weird size for an encrypted session key (%d)\n"
-msgstr "merkelig størrelse for en kryptert sesjonsnøkkel (%d)\n"
+msgstr "merkelig størrelse for en kryptert sesjonsnøkkel (%d)\n"
 
 #, c-format
 msgid "%s encrypted session key\n"
-msgstr ""
+msgstr "%s kryptert øktnøkkel\n"
 
 #, c-format
 msgid "passphrase generated with unknown digest algorithm %d\n"
-msgstr "passfrase er generert med en ukjent digest-algoritme %d\n"
+msgstr "passordfrase generert med ukjent summeringsalgoritme %d\n"
 
 #, c-format
 msgid "public key is %s\n"
-msgstr "offentlig nøkkel er %s\n"
+msgstr "offentlig nøkkel er %s\n"
 
 msgid "public key encrypted data: good DEK\n"
-msgstr "offentlig nøkkel-kryptert data: god DEK\n"
+msgstr "offentlig nøkkel-kryptert data: god DEK\n"
 
 #, c-format
 msgid "encrypted with %u-bit %s key, ID %s, created %s\n"
-msgstr "kryptert med %u-bit %s-nøkkel, ID %s, opprettet %s\n"
+msgstr "kryptert med %u-bit %s-nøkkel, ID %s, opprettet %s\n"
 
 # Do we really need to translate this string.
 # The must some bug in the code.
 #, c-format
 msgid "      \"%s\"\n"
-msgstr "      «%s»\n"
+msgstr "      Â«%s»\n"
 
 #, c-format
 msgid "encrypted with %s key, ID %s\n"
-msgstr "kryptert med %s-nøkkel, ID %s\n"
+msgstr "kryptert med %s-nøkkel, ID %s\n"
 
 #, c-format
 msgid "public key decryption failed: %s\n"
-msgstr "offentlig nøkkel-dekryptering mislyktes: %s\n"
+msgstr "offentlig nøkkel-dekryptering mislyktes: %s\n"
 
 #, c-format
 msgid "encrypted with %lu passphrases\n"
-msgstr ""
+msgstr "kryptert med %lu passordfraser\n"
 
 msgid "encrypted with 1 passphrase\n"
-msgstr ""
+msgstr "kryptert med 1 passordfrase\n"
 
 #, c-format
 msgid "assuming %s encrypted data\n"
-msgstr ""
+msgstr "antar %s kryptert data\n"
 
 #, c-format
 msgid "IDEA cipher unavailable, optimistically attempting to use %s instead\n"
-msgstr ""
+msgstr "IDEA-kryptering er utilgjengelig. Prøver å bruke %s i stedet\n"
 
 msgid "WARNING: message was not integrity protected\n"
-msgstr ""
+msgstr "ADVARSEL: meldinga var ikke integritetsbeskyttet\n"
 
 msgid "decryption okay\n"
-msgstr ""
+msgstr "dekryptering ok\n"
 
 msgid "WARNING: encrypted message has been manipulated!\n"
-msgstr ""
+msgstr "ADVARSEL: kryptert melding er blitt manipulert.\n"
 
 #, c-format
 msgid "decryption failed: %s\n"
 msgstr "dekryptering mislyktes: %s\n"
 
 msgid "Note: sender requested \"for-your-eyes-only\"\n"
-msgstr ""
+msgstr "Merk: senderen spesifiserte «kun for dine øyne»\n"
 
 #, c-format
 msgid "original file name='%.*s'\n"
-msgstr "opprinnelig filnavn=«%.*s»\n"
+msgstr "opprinnelig filnavn=«%.*s»\n"
 
 msgid "WARNING: multiple plaintexts seen\n"
-msgstr ""
+msgstr "ADVARSEL: fant flere elementer i ren tekst\n"
 
 msgid "standalone revocation - use \"gpg --import\" to apply\n"
-msgstr ""
+msgstr "selvstendig opphevelse - bruk «gpg --import» for å ta i bruk\n"
 
 msgid "no signature found\n"
-msgstr "ingen signatur ble funnet\n"
+msgstr "fant ikke signatur\n"
 
 #, c-format
 msgid "BAD signature from \"%s\""
-msgstr "DÅRLIG signatur fra «%s»"
+msgstr "DÃ\85RLIG signatur fra Â«%s»"
 
 #, c-format
 msgid "Expired signature from \"%s\""
-msgstr "Utgått signatur fra «%s»"
+msgstr "UtgÃ¥tt signatur fra Â«%s»"
 
 #, c-format
 msgid "Good signature from \"%s\""
-msgstr "God signatur fra «%s»"
+msgstr "God signatur fra Â«%s»"
 
 msgid "signature verification suppressed\n"
-msgstr ""
+msgstr "signaturbekreftelse ble hindret\n"
 
 msgid "can't handle this ambiguous signature data\n"
-msgstr ""
+msgstr "disse flertydige signaturdataene kan ikke behandles\n"
 
 #, c-format
 msgid "Signature made %s\n"
@@ -4525,37 +4369,36 @@ msgstr "Signatur opprettet %s\n"
 
 #, c-format
 msgid "               using %s key %s\n"
-msgstr "               bruker %s nøkkel %s\n"
+msgstr "               bruker %s nøkkel %s\n"
 
 #, c-format
 msgid "Signature made %s using %s key ID %s\n"
-msgstr "Signatur laget %s ved hjelp av %s-nøkkel ID %s\n"
+msgstr "Signatur laget %s ved hjelp av %s-nøkkel ID %s\n"
 
 msgid "Key available at: "
-msgstr "Nøkkel tilgjengelig ved: "
+msgstr "Nøkkel tilgjengelig ved: "
 
 msgid "[uncertain]"
 msgstr "[usikker]"
 
 #, c-format
 msgid "                aka \"%s\""
-msgstr "                aka «%s»"
+msgstr "                aka Â«%s»"
 
 #, c-format
 msgid "Signature expired %s\n"
-msgstr "Signatur utgått %s\n"
+msgstr "Signatur utgått %s\n"
 
 #, c-format
 msgid "Signature expires %s\n"
-msgstr "Signatur utgår %s\n"
+msgstr "Signatur utgår %s\n"
 
-#, fuzzy, c-format
-#| msgid "%s signature, digest algorithm %s\n"
+#, c-format
 msgid "%s signature, digest algorithm %s%s%s\n"
-msgstr "%s signatur, digestalgoritme %s\n"
+msgstr "%s-signatur, kontrollsum-algoritme %s%s%s\n"
 
 msgid "binary"
-msgstr "binær"
+msgstr "binær"
 
 msgid "textmode"
 msgstr "tekstmodus"
@@ -4563,37 +4406,34 @@ msgstr "tekstmodus"
 msgid "unknown"
 msgstr "ukjent"
 
-#, fuzzy
-#| msgid "unknown pubkey algorithm"
 msgid ", key algorithm "
-msgstr "ukjent pubkey-algoritme"
+msgstr ", nøkkelalgoritme"
 
 #, c-format
 msgid "WARNING: not a detached signature; file '%s' was NOT verified!\n"
-msgstr ""
+msgstr "ADVARSEL: ikke en separat signatur. Fila «%s» er IKKE bekreftet.\n"
 
 #, c-format
 msgid "Can't check signature: %s\n"
-msgstr ""
+msgstr "Klarte ikke å kontrollere signatur: %s\n"
 
 msgid "not a detached signature\n"
-msgstr ""
+msgstr "ikke en separat signatur\n"
 
 msgid ""
 "WARNING: multiple signatures detected.  Only the first will be checked.\n"
-msgstr ""
+msgstr "ADVARSEL: fant flere signaturer. Kontrollerer bare den første.\n"
 
 #, c-format
 msgid "standalone signature of class 0x%02x\n"
-msgstr ""
+msgstr "separat signatur av klasse 0x%02x\n"
 
 msgid "old style (PGP 2.x) signature\n"
-msgstr ""
+msgstr "gammeldags (PGP 2.x) signatur\n"
 
-#, fuzzy, c-format
-#| msgid "fstat(%d) failed in %s: %s\n"
+#, c-format
 msgid "fstat of '%s' failed in %s: %s\n"
-msgstr "fstat(%d) mislyktes in %s: %s\n"
+msgstr "fstat på «%s» mislyktes i %s: %s\n"
 
 #, c-format
 msgid "fstat(%d) failed in %s: %s\n"
@@ -4601,149 +4441,139 @@ msgstr "fstat(%d) mislyktes in %s: %s\n"
 
 #, c-format
 msgid "WARNING: using experimental public key algorithm %s\n"
-msgstr "ADVARSEL: bruker eksperimentell offentlig nøkkel-algoritme %s\n"
+msgstr "ADVARSEL: bruker eksperimentell offentlig nøkkel-algoritme %s\n"
 
-#, fuzzy
 msgid "WARNING: Elgamal sign+encrypt keys are deprecated\n"
-msgstr "ADVARSEL: digestalgoritmen «%s» er avlegs\n"
+msgstr "ADVARSEL: «Elgamal»-nøkler er utgått\n"
 
 #, c-format
 msgid "WARNING: using experimental cipher algorithm %s\n"
-msgstr "ADVARSEL: bruker eksperimentell cipheralgoritme %s\n"
+msgstr "ADVARSEL: bruker eksperimentell krypteringsalgoritme %s\n"
 
 #, c-format
 msgid "WARNING: using experimental digest algorithm %s\n"
-msgstr "ADVARSEL: bruker eksperimentell digest-algoritme %s\n"
+msgstr "ADVARSEL: bruker eksperimentell kontrollsum-algoritme %s\n"
 
 #, c-format
 msgid "WARNING: digest algorithm %s is deprecated\n"
-msgstr "ADVARSEL: digestalgoritmen «%s» er avlegs\n"
+msgstr "ADVARSEL: kontrollsum-algoritmen «%s» er utgått\n"
 
-#, fuzzy, c-format
-#| msgid "%s signature, digest algorithm %s\n"
+#, c-format
 msgid "Note: signatures using the %s algorithm are rejected\n"
-msgstr "%s signatur, digestalgoritme %s\n"
+msgstr "Merk: signaturer som bruker algoritmen %s blir avvist\n"
 
-#, fuzzy, c-format
-#| msgid "read error in `%s': %s\n"
+#, c-format
 msgid "(reported error: %s)\n"
-msgstr "lesefeil ved «%s»: %s\n"
+msgstr "(rapportert feil: %s)\n"
 
-#, fuzzy, c-format
-#| msgid "read error in `%s': %s\n"
+#, c-format
 msgid "(reported error: %s <%s>)\n"
-msgstr "lesefeil ved «%s»: %s\n"
+msgstr "(rapportert feil: %s <%s>)\n"
 
 msgid "(further info: "
-msgstr ""
+msgstr "(mer info: "
 
 #, c-format
 msgid "%s:%d: deprecated option \"%s\"\n"
-msgstr ""
+msgstr "%s:%d: valget «%s» er utgått\n"
 
 #, c-format
 msgid "WARNING: \"%s\" is a deprecated option\n"
-msgstr ""
+msgstr "ADVARSEL: valget «%s» er utgått\n"
 
 #, c-format
 msgid "please use \"%s%s\" instead\n"
-msgstr ""
+msgstr "bruk heller «%s%s»\n"
 
 #, c-format
 msgid "WARNING: \"%s\" is a deprecated command - do not use it\n"
-msgstr ""
+msgstr "ADVARSEL: «%s» er en utgått kommando. Ikke bruk den\n"
 
 #, c-format
 msgid "%s:%u: \"%s\" is obsolete in this file - it only has effect in %s\n"
-msgstr ""
+msgstr "%s:%u: «%s» er utgått i denne fila, og påvirker bare %s\n"
 
 #, c-format
 msgid ""
 "WARNING: \"%s%s\" is an obsolete option - it has no effect except on %s\n"
-msgstr ""
+msgstr "ADVARSEL: valget «%s%s» er utgått, og påvirker bare %s\n"
 
 msgid "Uncompressed"
-msgstr ""
+msgstr "Ukomprimert"
 
 #. TRANSLATORS: See doc/TRANSLATE about this string.
 msgid "uncompressed|none"
-msgstr ""
+msgstr "ukomprimert|ingen"
 
 #, c-format
 msgid "this message may not be usable by %s\n"
-msgstr ""
+msgstr "denne meldinga kan kanskje ikke brukes av %s\n"
 
-#, fuzzy, c-format
-#| msgid "ambiguous option `%s'\n"
+#, c-format
 msgid "ambiguous option '%s'\n"
-msgstr "flertydig valg «%s»\n"
+msgstr "«%s» er et flertydig valg\n"
 
-#, fuzzy, c-format
-#| msgid "unknown option `%s'\n"
+#, c-format
 msgid "unknown option '%s'\n"
-msgstr "ukjent valg «%s»\n"
+msgstr "«%s» er et ukjent valg\n"
 
 msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
+"Offentlig ECDSA-nøkler forventes i SEC-koding som kan ganges med 8 bit\n"
 
-#, fuzzy, c-format
-#| msgid "Unknown signature type `%s'\n"
+#, c-format
 msgid "unknown weak digest '%s'\n"
-msgstr "Ukjent signaturtype «%s»\n"
+msgstr "«%s» er en ukjent svak summeringsmetode\n"
 
-#, fuzzy, c-format
-#| msgid "File `%s' exists. "
+#, c-format
 msgid "File '%s' exists. "
-msgstr "Fila «%s» finnes. "
+msgstr "Fila Â«%s» finnes. "
 
 msgid "Overwrite? (y/N) "
 msgstr "Overskrive (j/N) "
 
 #, c-format
 msgid "%s: unknown suffix\n"
-msgstr ""
+msgstr "%s: ukjent suffiks\n"
 
 msgid "Enter new filename"
-msgstr "Tast inn nytt filnavn"
+msgstr "Skriv inn nytt filnavn"
 
 msgid "writing to stdout\n"
 msgstr "skriver til stdout\n"
 
-#, fuzzy, c-format
-#| msgid "assuming signed data in `%s'\n"
+#, c-format
 msgid "assuming signed data in '%s'\n"
-msgstr "antar at signert data er i «%s»\n"
+msgstr "antar signert data i Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "new configuration file `%s' created\n"
+#, c-format
 msgid "new configuration file '%s' created\n"
-msgstr "ny konfigurasjonsfil «%s» ble opprettet\n"
+msgstr "ny oppsettsfil «%s» opprettet\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: options in `%s' are not yet active during this run\n"
+#, c-format
 msgid "WARNING: options in '%s' are not yet active during this run\n"
-msgstr "ADVARSEL: valgene i «%s» er ikke aktive under denne kjøringen\n"
+msgstr "ADVARSEL: valgene i «%s» trer ikke i kraft for gjeldende programøkt\n"
 
 #, c-format
 msgid "can't handle public key algorithm %d\n"
-msgstr ""
+msgstr "klarte ikke å håndtere offentlig nøkkelalgoritme %d\n"
 
 msgid "WARNING: potentially insecure symmetrically encrypted session key\n"
-msgstr ""
+msgstr "ADVARSEL: det er usikkert å kryptere øktnøkkel symmetrisk\n"
 
 #, c-format
 msgid "subpacket of type %d has critical bit set\n"
-msgstr ""
+msgstr "underpakke %d er merket som kritisk\n"
 
 #, c-format
 msgid "problem with the agent: %s\n"
-msgstr ""
+msgstr "problem med agent: %s\n"
 
 #, c-format
 msgid " (main key ID %s)"
-msgstr " (hovednøkkelid %s)"
+msgstr " (hovednøkkelid %s)"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Please enter the passphrase to unlock the secret key for the OpenPGP "
 "certificate:\n"
@@ -4751,75 +4581,66 @@ msgid ""
 "%u-bit %s key, ID %s,\n"
 "created %s%s.\n"
 msgstr ""
-"Du trenger en passfrase for å låse opp den hemmelige nøkkelen for brukeren:\n"
-"«%.*s»\n"
-"%u-bit %s nøkkel, ID %s, opprettet %s%s\n"
+"Skriv inn passordfrase for å låse opp hemmelig nøkkel til OpenPGP-"
+"sertifikat:\n"
+"«%.*s»\n"
+"%u-bit %s-nøkkel, ID %s,\n"
+"opprettet %s%s.\n"
 
 msgid "Enter passphrase\n"
-msgstr "Tast inn passfrase\n"
+msgstr "Skriv inn passordfrase\n"
 
 msgid "cancelled by user\n"
-msgstr ""
+msgstr "avbrutt av bruker\n"
 
 #, c-format
 msgid ""
 "You need a passphrase to unlock the secret key for\n"
 "user: \"%s\"\n"
 msgstr ""
-"Du trenger en passfrase for å låse opp den hemmelige nøkkelen for\n"
-"brukeren: «%s»\n"
+"Du trenger en passordfrase for å låse opp hemmelig nøkkel for\n"
+"brukeren Â«%s»\n"
 
 #, c-format
 msgid "%u-bit %s key, ID %s, created %s"
-msgstr "%u-bit %s-nøkkel, ID %s, opprettet %s"
+msgstr "%u-bit %s-nøkkel, ID %s, opprettet %s"
 
 #, c-format
 msgid "         (subkey on main key ID %s)"
-msgstr ""
+msgstr "         (undernøkkel av hovednøkkel-ID %s)"
 
-#, fuzzy
 msgid "Please enter the passphrase to unlock the OpenPGP secret key:"
-msgstr ""
-"Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-"\n"
+msgstr "Skriv inn passordfrase for å låse opp hemmelig OpenPGP-nøkkel:"
 
-#, fuzzy
 msgid "Please enter the passphrase to import the OpenPGP secret key:"
-msgstr ""
-"Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-"\n"
+msgstr "Skriv inn passordfrase for å importere hemmelig OpenPGP-nøkkel:"
 
-#, fuzzy
 msgid "Please enter the passphrase to export the OpenPGP secret subkey:"
-msgstr ""
-"Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-"\n"
+msgstr "Skriv inn passordfrase for å eksportere hemmelig OpenPGP-undernøkkel:"
 
-#, fuzzy
 msgid "Please enter the passphrase to export the OpenPGP secret key:"
-msgstr ""
-"Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-"\n"
+msgstr "Skriv inn passordfrase for å eksportere hemmelig OpenPGP-nøkkel:"
 
-#, fuzzy
-#| msgid "Do you really want to delete the selected keys? (y/N) "
 msgid "Do you really want to permanently delete the OpenPGP secret subkey key:"
-msgstr "Vil du virkelig slette den valgte nøkkelen? (j/N) "
+msgstr ""
+"Er du sikker på at du vil slette følgende hemmelige OpenPGP-undernøkkel:"
 
-#, fuzzy
-#| msgid "Do you really want to delete the selected keys? (y/N) "
 msgid "Do you really want to permanently delete the OpenPGP secret key:"
-msgstr "Vil du virkelig slette den valgte nøkkelen? (j/N) "
+msgstr "Er du sikker på at du vil slette følgende hemmelige OpenPGP-nøkkel:"
 
-#, fuzzy, c-format
-#| msgid "%u-bit %s key, ID %s, created %s"
+#, c-format
 msgid ""
 "%s\n"
 "\"%.*s\"\n"
 "%u-bit %s key, ID %s,\n"
 "created %s%s.\n"
 "%s"
-msgstr "%u-bit %s-nøkkel, ID %s, opprettet %s"
+msgstr ""
+"%s\n"
+"«%.*s»\n"
+"%u-bit %s-nøkkel, ID %s,\n"
+"opprettet %s%s.\n"
+"%s"
 
 msgid ""
 "\n"
@@ -4828,47 +4649,50 @@ msgid ""
 "very large picture, your key will become very large as well!\n"
 "Keeping the image close to 240x288 is a good size to use.\n"
 msgstr ""
+"\n"
+"Velg et bilde som skal brukes som foto-ID. Bildet må være i JPEG-format.\n"
+"Husk at bildet lagres som en del av den offentlige nøkkelen, og at\n"
+"nøkkelstørrelsen derfor påvirkes av hvor stort bildet er.\n"
+"En oppløsning på rundt 240x288 piksler er et godt utgangspunkt.\n"
 
 msgid "Enter JPEG filename for photo ID: "
-msgstr ""
+msgstr "Skriv inn JPEG-filnavn for foto-ID: "
 
-#, fuzzy, c-format
-#| msgid "unable to open JPEG file `%s': %s\n"
+#, c-format
 msgid "unable to open JPEG file '%s': %s\n"
-msgstr "kan ikke åpne JPEG-fil «%s»: %s\n"
+msgstr "klarte ikke Ã¥ Ã¥pne JPEG-fil Â«%s»: %s\n"
 
 #, c-format
 msgid "This JPEG is really large (%d bytes) !\n"
-msgstr ""
+msgstr "Denne JPEG-fila er veldig stor (%d byte).\n"
 
 msgid "Are you sure you want to use it? (y/N) "
-msgstr "Er du sikker på at du vil bruke den? (j/N) "
+msgstr "Er du sikker på at du vil bruke den? (j/N) "
 
-#, fuzzy, c-format
-#| msgid "`%s' is not a JPEG file\n"
+#, c-format
 msgid "'%s' is not a JPEG file\n"
-msgstr "«%s» er ikke et JPEG-fil\n"
+msgstr "«%s» er ikke en JPEG-fil\n"
 
 msgid "Is this photo correct (y/N/q)? "
-msgstr ""
+msgstr "Er dette bildet riktig (j/N/q)? "
 
 msgid "unable to display photo ID!\n"
-msgstr ""
+msgstr "klarte ikke å vise foto-ID.\n"
 
 msgid "No reason specified"
-msgstr "Ingen grunn er angitt"
+msgstr "Ingen grunn oppgitt"
 
 msgid "Key is superseded"
-msgstr "Nøkkelen er overgått"
+msgstr "Nøkkelen er overgått"
 
 msgid "Key has been compromised"
-msgstr "Nøkkelen har blitt kompromittert"
+msgstr "Nøkkelen har blitt kompromittert"
 
 msgid "Key is no longer used"
-msgstr "Nøkkelen er ikke lengre i bruk"
+msgstr "Nøkkelen er ikke lengre i bruk"
 
 msgid "User ID is no longer valid"
-msgstr "Brukerid er ikke lengre gyldig"
+msgstr "Bruker-ID er ikke lenger gyldig"
 
 msgid "reason for revocation: "
 msgstr "grunnen for opphevelse: "
@@ -4894,13 +4718,12 @@ msgstr "Ingen tillitsverdi tilordnet til:\n"
 
 #, c-format
 msgid "  aka \"%s\"\n"
-msgstr "  aka «%s»\n"
+msgstr "  aka Â«%s»\n"
 
 msgid ""
 "How much do you trust that this key actually belongs to the named user?\n"
 msgstr ""
-"Hvor mye stoler du på at denne nøkkelen faktisk tilhører den angitte "
-"brukeren?\n"
+"Hvor mye stoler du på at denne nøkkelen faktisk tilhører navngitt bruker?\n"
 
 #, c-format
 msgid "  %d = I don't know or won't say\n"
@@ -4908,17 +4731,17 @@ msgstr "  %d = Jeg vet ikke eller vil ikke uttale meg\n"
 
 #, c-format
 msgid "  %d = I do NOT trust\n"
-msgstr "  %d = Jeg stoler IKKE på den\n"
+msgstr "  %d = Jeg stoler IKKE på den\n"
 
 #, c-format
 msgid "  %d = I trust ultimately\n"
-msgstr "  %d = Jeg stoler fullstendig på den\n"
+msgstr "  %d = Jeg stoler fullstendig på den\n"
 
 msgid "  m = back to the main menu\n"
 msgstr "  m = tilbake til hovedmenyen\n"
 
 msgid "  s = skip this key\n"
-msgstr "  s = hopp over denne nøkkelen\n"
+msgstr "  s = hopp over denne nøkkelen\n"
 
 msgid "  q = quit\n"
 msgstr "  q = avslutt\n"
@@ -4928,96 +4751,97 @@ msgid ""
 "The minimum trust level for this key is: %s\n"
 "\n"
 msgstr ""
+"Laveste tillitsnivå for denne nøkkelen er: %s\n"
+"\n"
 
 msgid "Your decision? "
-msgstr "Valget ditt? "
+msgstr "Hva velger du? "
 
 msgid "Do you really want to set this key to ultimate trust? (y/N) "
-msgstr "Vil du virkelig sette denne nøkkelen til fullstendig tillit? (j/N) "
+msgstr "Er du sikker på at du vil gi denne nøkkelen fullstendig tillit? (j/N) "
 
 msgid "Certificates leading to an ultimately trusted key:\n"
-msgstr "Sertifikater som fører til en fullstendig betrodd nøkkel:\n"
+msgstr "Sertifikater som fører til en fullstendig betrodd nøkkel:\n"
 
 #, c-format
 msgid "%s: There is no assurance this key belongs to the named user\n"
 msgstr ""
-"%s: Det finnes ingen indikasjon på at denne nøkkelen faktisk tilhører den "
-"angitte eieren\n"
+"%s: Det finnes ingen indikasjon på at denne nøkkelen faktisk tilhører "
+"navngitt bruker\n"
 
 #, c-format
 msgid "%s: There is limited assurance this key belongs to the named user\n"
 msgstr ""
-"%s: Det er begrenset indikasjon på at denne nøkkelen faktisk tilhører den "
-"angitte eieren\n"
+"%s: Det er begrenset indikasjon på at denne nøkkelen faktisk tilhører "
+"navngitt bruker\n"
 
 msgid "This key probably belongs to the named user\n"
-msgstr "Denne nøkkelen tilhører sannsynligvis den angitte eieren\n"
+msgstr "Denne nøkkelen tilhører sannsynligvis navngitt bruker\n"
 
 msgid "This key belongs to us\n"
-msgstr "denne nøkkelen tilhører oss\n"
+msgstr "denne nøkkelen tilhører oss\n"
 
 msgid ""
 "It is NOT certain that the key belongs to the person named\n"
 "in the user ID.  If you *really* know what you are doing,\n"
 "you may answer the next question with yes.\n"
 msgstr ""
-"Det er IKKE sikkert at nøkkelen tilhører personen som er angitt i\n"
-"brukeriden.  Dersom du *virkelig* vet hva du gjør, kan du besvare det\n"
-"neste spørsmålet med ja.\n"
+"Det er IKKE sikkert at nøkkelen tilhører personen som er navngitt i\n"
+"bruker-id-en.  Hvis du *virkelig* vet hva du gjør, kan du svare ja\n"
+"på neste spørsmål.\n"
 
 msgid "Use this key anyway? (y/N) "
-msgstr "Bruke denne nøkkelen likevel? (j/N) "
+msgstr "Vil du bruke denne nøkkelen likevel? (j/N) "
 
 msgid "WARNING: Using untrusted key!\n"
-msgstr "ADVARSEL: Bruker ubetrodd nøkkel!\n"
+msgstr "ADVARSEL: du bruker en upålitelig nøkkel.\n"
 
 msgid "WARNING: this key might be revoked (revocation key not present)\n"
 msgstr ""
-"ADVARSEL: nøkkel %s kan være opphevet: opphevingsnøkkel %s ikke tilstede.\n"
+"ADVARSEL: nøkkel %s kan være opphevet: opphevingsnøkkel %s ikke tilstede.\n"
 
 msgid "WARNING: This key has been revoked by its designated revoker!\n"
-msgstr ""
-"ADVARSEL: Denne nøkkelen har blitt opphevet av den utpekte oppheveren!\n"
+msgstr "ADVARSEL: denne nøkkelen er opphevet.\n"
 
 msgid "WARNING: This key has been revoked by its owner!\n"
-msgstr "ADVARSEL: Denne nøkkelen har blitt opphevet av dens eier!\n"
+msgstr "ADVARSEL: denne nøkkelen er opphevet av eieren.\n"
 
 msgid "         This could mean that the signature is forged.\n"
 msgstr "         Dette kan bety at signaturen er falsk.\n"
 
 msgid "WARNING: This subkey has been revoked by its owner!\n"
-msgstr "ADVARSEL: Denne undernøkkelen har blitt opphevet av eieren!\n"
+msgstr "ADVARSEL: denne undernøkkelen er opphevet av eieren.\n"
 
 msgid "Note: This key has been disabled.\n"
-msgstr "Merk: Denne nøkkelen har blitt utkoblet.\n"
+msgstr "Merk: Denne nøkkelen er ikke i bruk.\n"
 
 #, c-format
 msgid "Note: Verified signer's address is '%s'\n"
-msgstr ""
+msgstr "Merk: Bekreftet signeringsadresse er «%s»\n"
 
 #, c-format
 msgid "Note: Signer's address '%s' does not match DNS entry\n"
-msgstr ""
+msgstr "Merk: Signeringsadresse «%s» samsvarer ikke med DNS-oppslag\n"
 
 msgid "trustlevel adjusted to FULL due to valid PKA info\n"
-msgstr ""
+msgstr "tillitsnivå oppjustert til «FULL» pga. gyldig PKA-info\n"
 
 msgid "trustlevel adjusted to NEVER due to bad PKA info\n"
-msgstr ""
+msgstr "tillitsnivå nedjustert til «NEVER» (aldri) pga. ugyldig PKA-info\n"
 
 msgid "Note: This key has expired!\n"
-msgstr "Merk: Denne nøkkelen er utgått!\n"
+msgstr "Merk: denne nøkkelen er utgått.\n"
 
 msgid "WARNING: This key is not certified with a trusted signature!\n"
 msgstr ""
-"ADVARSEL: Denne nøkkelen er ikke sertifisert med en betrodd signatur!\n"
+"ADVARSEL: denne nøkkelen er ikke sertifisert med en tillitsverdig signatur.\n"
 
 msgid ""
 "         There is no indication that the signature belongs to the owner.\n"
-msgstr "         Det er ingen indikasjon på at signaturen tilhører eieren.\n"
+msgstr "         Det er ingen indikasjon på at signaturen tilhører eieren.\n"
 
 msgid "WARNING: We do NOT trust this key!\n"
-msgstr "ADVARSEL: Vi stoler IKKE på denne nøkkelen!\n"
+msgstr "ADVARSEL: vi stoler IKKE på denne nøkkelen.\n"
 
 msgid "         The signature is probably a FORGERY.\n"
 msgstr "         Signaturen er sannsynligvis et FALSKNERI.\n"
@@ -5025,11 +4849,11 @@ msgstr "         Signaturen er sannsynligvis et FALSKNERI.\n"
 msgid ""
 "WARNING: This key is not certified with sufficiently trusted signatures!\n"
 msgstr ""
-"ADVARSEL: Denne nøkkelen er ikke sertifisert med tilstrekkelige betrodde "
-"signaturer!\n"
+"ADVARSEL: denne nøkkelen er ikke sertifisert med tilstrekkelig "
+"tillitsverdige signaturer.\n"
 
 msgid "         It is not certain that the signature belongs to the owner.\n"
-msgstr "         Det er ikke sikkert at signaturen tilhører brukeren.\n"
+msgstr "         Det er ikke sikkert at signaturen tilhører brukeren.\n"
 
 #, c-format
 msgid "%s: skipped: %s\n"
@@ -5037,162 +4861,157 @@ msgstr "%s: hoppet over: %s\n"
 
 #, c-format
 msgid "%s: skipped: public key is disabled\n"
-msgstr "%s: hoppet over: offentlig nøkkel er utkoblet\n"
+msgstr "%s: hoppet over. Offentlig nøkkel er ikke i bruk\n"
 
 #, c-format
 msgid "%s: skipped: public key already present\n"
-msgstr "%s: hoppet over: offentlig nøkkel er allerede tilstede\n"
+msgstr "%s: hoppet over: offentlig nøkkel er allerede tilstede\n"
 
-#, fuzzy, c-format
-#| msgid "can't close `%s': %s\n"
+#, c-format
 msgid "can't encrypt to '%s'\n"
-msgstr "kan ikke lukke «%s»: %s\n"
+msgstr "klarte ikke å kryptere til «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "option '%s' given, but no valid default keys given\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "valgt «%s», men mangler gyldig forvalgt nøkkel\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "option '%s' given, but option '%s' not given\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "valgt Â«%s», men mangler valget Â«%s»\n"
 
 msgid "You did not specify a user ID. (you may use \"-r\")\n"
-msgstr "Du oppga ikke en brukerid. (Du kan bruke «-r»)\n"
+msgstr "Du skrev ikke inn en bruker-ID. (bruk evt. Â«-r»)\n"
 
 msgid "Current recipients:\n"
-msgstr ""
+msgstr "Gjeldende mottakere:\n"
 
 msgid ""
 "\n"
 "Enter the user ID.  End with an empty line: "
 msgstr ""
 "\n"
-"Tast inn brukeriden.  Avslutt med en blank linje: "
+"Skriv inn bruker-ID og avslutt med tom linje: "
 
 msgid "No such user ID.\n"
-msgstr "Det finnes ingen slik brukerid.\n"
+msgstr "Bruker-id-en finnes ikke.\n"
 
 msgid "skipped: public key already set as default recipient\n"
-msgstr "hoppet over: offentlig nøkkel allerede satt som standard mottaker\n"
+msgstr "hoppet over: offentlig nøkkel allerede valgt som standardmottaker\n"
 
 msgid "Public key is disabled.\n"
-msgstr "Offentlig nøkkel er utkoblet.\n"
+msgstr "Offentlig nøkkel er ikke i bruk.\n"
 
 msgid "skipped: public key already set\n"
-msgstr "hoppet over: offentlig nøkkel er allerede satt\n"
+msgstr "hoppet over: offentlig nøkkel er allerede valgt\n"
 
 #, c-format
 msgid "unknown default recipient \"%s\"\n"
-msgstr "ukjent standardmottaker «%s»\n"
+msgstr "«%s» er en ukjent standardmottaker\n"
 
 msgid "no valid addressees\n"
-msgstr "ingen gyldige adressater\n"
+msgstr "ingen gyldige mottakere\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Note: key %s has no %s feature\n"
-msgstr "nøkkel %s: ingen brukerid\n"
+msgstr "Merk: nøkkel %s har ingen %s-funksjon\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Note: key %s has no preference for %s\n"
-msgstr "nøkkel %s: ingen brukerid\n"
+msgstr "Merk: nøkkel %s har ingen innstilling for %s\n"
 
 msgid "data not saved; use option \"--output\" to save it\n"
-msgstr ""
+msgstr "data ble ikke lagret. Bruk valget «--output» for å lagre\n"
 
 msgid "Detached signature.\n"
-msgstr ""
+msgstr "Adskilt signatur.\n"
 
 msgid "Please enter name of data file: "
-msgstr ""
+msgstr "Skriv inn navn på datafil: "
 
 msgid "reading stdin ...\n"
-msgstr ""
+msgstr "leser std.innkanal …\n"
 
 msgid "no signed data\n"
-msgstr ""
+msgstr "ingen signerte data\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't open signed data '%s'\n"
-msgstr "kan ikke åpne «%s»: %s\n"
+msgstr "klarte ikke å åpne signert data «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't open signed data fd=%d: %s\n"
-msgstr "kan ikke åpne «%s»: %s\n"
+msgstr "klarte ikke å åpne signert data fd=%d: «%s»\n"
 
 #, c-format
 msgid "anonymous recipient; trying secret key %s ...\n"
-msgstr ""
+msgstr "anonym mottaker. prøver hemmelig nøkkel %s …\n"
 
 msgid "okay, we are the anonymous recipient.\n"
-msgstr ""
+msgstr "ok, det er du som er den anonyme mottakeren.\n"
 
 msgid "old encoding of the DEK is not supported\n"
-msgstr ""
+msgstr "gammel DEK-koding støttes ikke\n"
 
 #, c-format
 msgid "cipher algorithm %d%s is unknown or disabled\n"
-msgstr ""
+msgstr "krypteringsalgoritme %d%s er ukjent eller slått av\n"
 
 #, c-format
 msgid "WARNING: cipher algorithm %s not found in recipient preferences\n"
-msgstr ""
-"påtvinging av kompresjonsalgoritme %s bryter med mottakerens preferanser\n"
+msgstr "ADVARSEL: fant ikke krypteringsalgoritme %s i mottakers oppsett\n"
 
-#, fuzzy, c-format
-#| msgid "NOTE: secret key %s expired at %s\n"
+#, c-format
 msgid "Note: secret key %s expired at %s\n"
-msgstr "NOTIS: hemmelig nøkkel %s utgikk den %s\n"
+msgstr "Merk: hemmelig nøkkel %s utgått %s\n"
 
-#, fuzzy
 msgid "Note: key has been revoked"
-msgstr "NOTIS: signaturnøkkelen %s utgikk %s\n"
+msgstr "Merk: nøkkelen er opphevet"
 
 #, c-format
 msgid "build_packet failed: %s\n"
-msgstr ""
+msgstr "build_packet mislyktes. %s\n"
 
 #, c-format
 msgid "key %s has no user IDs\n"
-msgstr "nøkkel %s: ingen brukerid\n"
+msgstr "nøkkel %s: ingen bruker-ID\n"
 
 msgid "To be revoked by:\n"
-msgstr ""
+msgstr "Skal oppheves av:\n"
 
 msgid "(This is a sensitive revocation key)\n"
-msgstr ""
+msgstr "(Dette er en privat opphevelsesnøkkel)\n"
 
-#, fuzzy
-#| msgid "Secret key is available.\n"
 msgid "Secret key is not available.\n"
-msgstr "Hemmelig nøkkel er tilgjengelig\n"
+msgstr "Hemmelig nøkkel er ikke tilgjengelig.\n"
 
 msgid "Create a designated revocation certificate for this key? (y/N) "
-msgstr "Lage et utpekt opphevingssertifikat for denne nøkkelen? (j/N) "
+msgstr "Vil du lage et utpekt opphevelsessertifikat for denne nøkkelen? (j/N) "
 
 msgid "ASCII armored output forced.\n"
-msgstr ""
+msgstr "Tvunget ASCII-armert utdata.\n"
 
 #, c-format
 msgid "make_keysig_packet failed: %s\n"
-msgstr ""
+msgstr "make_keysig_packet mislyktes: %s\n"
 
 msgid "Revocation certificate created.\n"
-msgstr ""
+msgstr "Opphevelsessertifikat opprettet.\n"
 
 #, c-format
 msgid "no revocation keys found for \"%s\"\n"
-msgstr ""
+msgstr "fant ingen opphevelsesnøkler for «%s»\n"
 
-#, fuzzy
-#| msgid "Create a revocation certificate for this key? (y/N) "
 msgid "This is a revocation certificate for the OpenPGP key:"
-msgstr "Lage et opphevingssertifikat for denne nøkkelen? (j/N) "
+msgstr "Dette er et opphevelsessertifikat for følgende OpenPGP-nøkkel:"
 
 msgid ""
 "A revocation certificate is a kind of \"kill switch\" to publicly\n"
 "declare that a key shall not anymore be used.  It is not possible\n"
 "to retract such a revocation certificate once it has been published."
 msgstr ""
+"Et opphevelsessertifikat er en slags nødknapp som lar deg\n"
+"\verklære offentlig at en nøkkel ikke skal brukes mer. Det er ikke mulig\n"
+"å trekke tilbake en oppheving straks den er blitt publisert."
 
 msgid ""
 "Use it to revoke this key in case of a compromise or loss of\n"
@@ -5201,37 +5020,43 @@ msgid ""
 "a reason for the revocation.  For details see the description of\n"
 "of the gpg command \"--gen-revoke\" in the GnuPG manual."
 msgstr ""
+"Bruk det for å oppheve denne nøkkelen hvis den blir kompromittert\n"
+"eller hvis du mister den hemmelige nøkkelen. Hvis du fremdeles har\n"
+"tilgang til den hemmelige nøkkelen, er det lurt å heller lage et nytt\n"
+"\vopphevelsessertifikat og oppgi en grunn til opphevelsen.\n"
+"\vSe beskrivelse av kommandoen «--gen-revoke» i GnuPG-\n"
+"bruksanvisninga for detaljer."
 
 msgid ""
 "To avoid an accidental use of this file, a colon has been inserted\n"
 "before the 5 dashes below.  Remove this colon with a text editor\n"
 "before importing and publishing this revocation certificate."
 msgstr ""
+"Et kolontegn er satt inn før 5 streker nedenfor.\n"
+"Fjern dette kolonet med en tekstbehandler før du importerer og\n"
+"publiserer opphevelsessertifikatet."
 
-#, fuzzy, c-format
-#| msgid "key %s: \"%s\" revocation certificate imported\n"
+#, c-format
 msgid "revocation certificate stored as '%s.rev'\n"
-msgstr "nøkkel %s: «%s» opphevingssertifikat importert\n"
+msgstr "opphevelsessertifikat lagret som «%s.rev»\n"
 
-#, fuzzy, c-format
-#| msgid "secret key \"%s\" not found: %s\n"
+#, c-format
 msgid "secret key \"%s\" not found\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "fant ikke hemmelig nøkkel «%s»\n"
 
 #. TRANSLATORS: The %s prints a key specification which
 #. for example has been given at the command line.  Several lines
 #. lines with secret key infos are printed after this message.
 #, c-format
 msgid "'%s' matches multiple secret keys:\n"
-msgstr ""
+msgstr "«%s» samsvarer med flere hemmelige nøkler:\n"
 
-#, fuzzy, c-format
-#| msgid "error creating keyring `%s': %s\n"
+#, c-format
 msgid "error searching the keyring: %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "feil under søk på nøkkelknippe: %s\n"
 
 msgid "Create a revocation certificate for this key? (y/N) "
-msgstr "Lage et opphevingssertifikat for denne nøkkelen? (j/N) "
+msgstr "Vil du lage et opphevelsessertifikat for denne nøkkelen? (j/N) "
 
 msgid ""
 "Revocation certificate created.\n"
@@ -5242,191 +5067,199 @@ msgid ""
 "your media become unreadable.  But have some caution:  The print system of\n"
 "your machine might store the data and make it available to others!\n"
 msgstr ""
+"Opphevelsessertifikat opprettet.\n"
+"\n"
+"Flytt dette til et medium du kan holde utenfor andres rekkevidde. Hvis "
+"Mallory\n"
+"får tak i dette sertifikatet, kan han bruke det til å gjøre nøkkelen din "
+"ubrukelig.\n"
+"Det er lurt å skrive ut dette sertifikatet fysisk og sette det på et lager i "
+"tilfelle\n"
+"datalagringsmediet blir uleselig. Men vær forsiktig. Datamaskinens\n"
+"utskriftssystem kan være satt opp til å lagre utskriftsdata og dermed gjøre\n"
+"det mulig for andre å lese sertifikatet.\n"
 
 msgid "Please select the reason for the revocation:\n"
-msgstr ""
+msgstr "Velg grunn for opphevelse:\n"
 
 msgid "Cancel"
-msgstr ""
+msgstr "Avbryt"
 
 #, c-format
 msgid "(Probably you want to select %d here)\n"
-msgstr ""
+msgstr "(Normalt bør du velge %d her)\n"
 
 msgid "Enter an optional description; end it with an empty line:\n"
-msgstr ""
+msgstr "Skriv inn en beskrivelse hvis du vil, og avslutt med tom linje:\n"
 
 #, c-format
 msgid "Reason for revocation: %s\n"
-msgstr ""
+msgstr "Grunnlag for opphevelse: %s\n"
 
 msgid "(No description given)\n"
-msgstr ""
+msgstr "(Ingen beskrivelse oppgitt)\n"
 
 msgid "Is this okay? (y/N) "
 msgstr "Er dette i orden? (j/N) "
 
 msgid "weak key created - retrying\n"
-msgstr "svak nøkkel ble opprettet - prøver på nytt\n"
+msgstr "nøkkelen ble svak. Prøver på nytt\n"
 
 #, c-format
 msgid "cannot avoid weak key for symmetric cipher; tried %d times!\n"
 msgstr ""
-"kan ikke unngå svak nøkkel for symmetrisk krypteringsalgorime; prøvde %d "
-"ganger!\n"
+"klarte ikke å unngå svak nøkkel for symmetrisk krypteringsalgorime. Prøvde "
+"%d ganger.\n"
 
 #, c-format
 msgid "%s key %s uses an unsafe (%zu bit) hash\n"
-msgstr ""
+msgstr "%s-nøkkel %s bruker usikker kontrollsum (%zu bit)\n"
 
 #, c-format
 msgid "%s key %s requires a %zu bit or larger hash (hash is %s)\n"
 msgstr ""
+"%s-nøkkel %s krever kontrollsum på %zu eller flere bit (gjeldende sum: %s)\n"
 
 msgid "WARNING: signature digest conflict in message\n"
-msgstr ""
+msgstr "ADVARSEL: konflikt med signatur-kontrollsum i melding\n"
 
 #, c-format
 msgid "WARNING: signing subkey %s is not cross-certified\n"
-msgstr ""
+msgstr "ADVARSEL: undernøkkel %s for signering er ikke kryssertifisert\n"
 
 #, c-format
 msgid "please see %s for more information\n"
-msgstr "vennligst se %s for mer informasjon\n"
+msgstr "se %s for mer informasjon\n"
 
 #, c-format
 msgid "WARNING: signing subkey %s has an invalid cross-certification\n"
 msgstr ""
+"ADVARSEL: undernøkkel %s for signering er kryssertifisert på ugyldig "
+"grunnlag\n"
 
 #, c-format
 msgid "public key %s is %lu second newer than the signature\n"
 msgid_plural "public key %s is %lu seconds newer than the signature\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "offentlig nøkkel %s er %lu sekund nyere enn signaturen\n"
+msgstr[1] "offentlig nøkkel %s er %lu sekunder nyere enn signaturen\n"
 
-#, fuzzy, c-format
-#| msgid "key %s: \"%s\" %d new signatures\n"
+#, c-format
 msgid "public key %s is %lu day newer than the signature\n"
 msgid_plural "public key %s is %lu days newer than the signature\n"
-msgstr[0] "nøkkel: %s: «%s» %d nye signaturer\n"
-msgstr[1] "nøkkel: %s: «%s» %d nye signaturer\n"
+msgstr[0] "offentlig nøkkel %s er %lu dag nyere enn signaturen\n"
+msgstr[1] "offentlig nøkkel %s er %lu dager nyere enn signaturen\n"
 
-# Er dette entallsformen av denne strengen?
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid ""
 "key %s was created %lu second in the future (time warp or clock problem)\n"
 msgid_plural ""
 "key %s was created %lu seconds in the future (time warp or clock problem)\n"
 msgstr[0] ""
-"nøkkel %s ble opprettet %lu sekund i fremtiden (time warp eller "
+"nøkkel %s ble opprettet %lu sekund i fremtiden (tidsforskyvnings- eller "
 "klokkeproblem)\n"
 msgstr[1] ""
-"nøkkel %s ble opprettet %lu sekund i fremtiden (time warp eller "
+"nøkkel %s ble opprettet %lu sekunder i fremtiden (tidsforskyvnings- eller "
 "klokkeproblem)\n"
 
-# Er dette entallsformen av denne strengen?
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid "key %s was created %lu day in the future (time warp or clock problem)\n"
 msgid_plural ""
 "key %s was created %lu days in the future (time warp or clock problem)\n"
 msgstr[0] ""
-"nøkkel %s ble opprettet %lu sekund i fremtiden (time warp eller "
+"nøkkel %s ble opprettet %lu dag i fremtiden (tidsforskyvnings- eller "
 "klokkeproblem)\n"
 msgstr[1] ""
-"nøkkel %s ble opprettet %lu sekund i fremtiden (time warp eller "
+"nøkkel %s ble opprettet %lu dager i fremtiden (tidsforskyvnings- eller "
 "klokkeproblem)\n"
 
-#, fuzzy, c-format
-#| msgid "NOTE: signature key %s expired %s\n"
+#, c-format
 msgid "Note: signature key %s expired %s\n"
-msgstr "NOTIS: signaturnøkkelen %s utgikk %s\n"
+msgstr "Merk: signaturnøkkel %s utgått %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Note: signature key %s has been revoked\n"
-msgstr "NOTIS: signaturnøkkelen %s utgikk %s\n"
+msgstr "Merk: signaturnøkkel %s er opphevet\n"
 
 #, c-format
 msgid "assuming bad signature from key %s due to an unknown critical bit\n"
-msgstr ""
+msgstr "antatt ugyldig signatur fra nøkkel %s pga. ukjent «kritisk»-bit\n"
 
 #, c-format
 msgid "key %s: no subkey for subkey revocation signature\n"
-msgstr "nøkkel %s: ingen undernøkkel for undernøkkelopphevingssignatur\n"
+msgstr "nøkkel %s: ingen undernøkkel for undernøkkelopphevingssignatur\n"
 
 #, c-format
 msgid "key %s: no subkey for subkey binding signature\n"
-msgstr "nøkkel %s: ingen undernøkkel for undernøkkelbindingssignatur\n"
+msgstr "nøkkel %s: ingen undernøkkel for undernøkkelbindingssignatur\n"
 
 #, c-format
 msgid "WARNING: unable to %%-expand notation (too large).  Using unexpanded.\n"
-msgstr ""
+msgstr "ADVARSEL: klarte ikke å %%-utvide notasjon (for lang).\n"
 
 #, c-format
 msgid ""
 "WARNING: unable to %%-expand policy URL (too large).  Using unexpanded.\n"
-msgstr ""
+msgstr "ADVARSEL: klarte ikke å %%-utvide regelverkadresse (for lang).\n"
 
 #, c-format
 msgid ""
 "WARNING: unable to %%-expand preferred keyserver URL (too large).  Using "
 "unexpanded.\n"
 msgstr ""
+"ADVARSEL: klarte ikke å %%-utvide foretrukket nøkkeltjener-adresse (for "
+"lang).\n"
 
 #, c-format
 msgid "%s/%s signature from: \"%s\"\n"
-msgstr "%s/%s-signatur fra: «%s»\n"
+msgstr "%s/%s-signatur fra: Â«%s»\n"
 
 #, c-format
 msgid ""
 "WARNING: forcing digest algorithm %s (%d) violates recipient preferences\n"
-msgstr ""
-"ADVARSEL: påtvinging av kompresjonsalgoritme %s (%d) bryter med mottakerens "
-"preferanser\n"
+msgstr "ADVARSEL: tvungen bruk av %s (%d) bryter med mottakerens oppsett\n"
 
 msgid "signing:"
-msgstr ""
+msgstr "signerer:"
 
 #, c-format
 msgid "%s encryption will be used\n"
-msgstr ""
+msgstr "bruker %s-kryptering\n"
 
 msgid "key is not flagged as insecure - can't use it with the faked RNG!\n"
-msgstr ""
+msgstr "nøkkel er ikke merket som usikker, og kan ikke brukes med falsk RNG.\n"
 
 #, c-format
 msgid "skipped \"%s\": duplicated\n"
-msgstr "hoppet over «%s»: er duplikat\n"
+msgstr "hoppet over Â«%s»: er duplikat\n"
 
 msgid "skipped: secret key already present\n"
-msgstr ""
+msgstr "hoppet over, fordi hemmelig nøkkel allerede er tilstede\n"
 
 msgid "this is a PGP generated Elgamal key which is not secure for signatures!"
 msgstr ""
+"dette er en PGP-generelt Elgamal-nøkkel, og egner seg ikke til signering."
 
 #, c-format
 msgid "trust record %lu, type %d: write failed: %s\n"
-msgstr ""
+msgstr "tillitsoppføring %lu, type %d: skriving mislyktes. %s\n"
 
 #, c-format
 msgid ""
 "# List of assigned trustvalues, created %s\n"
 "# (Use \"gpg --import-ownertrust\" to restore them)\n"
 msgstr ""
+"# Liste over tildelte tillitsverdier, opprettet %s\n"
+"# (Bruk «gpg --import-ownertrust» for å gjenopprette disse)\n"
 
-#, fuzzy, c-format
-#| msgid "error in `%s': %s\n"
+#, c-format
 msgid "error in '%s': %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil i Â«%s»: %s\n"
 
 msgid "line too long"
 msgstr "for lang linje"
 
 msgid "colon missing"
-msgstr ""
+msgstr "kolon mangler"
 
 msgid "invalid fingerprint"
 msgstr "ugyldig fingeravtrykk"
@@ -5434,330 +5267,323 @@ msgstr "ugyldig fingeravtrykk"
 msgid "ownertrust value missing"
 msgstr "verdi for eiertillit mangler"
 
-#, fuzzy, c-format
-#| msgid "error finding trust record in `%s': %s\n"
+#, c-format
 msgid "error finding trust record in '%s': %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under søk etter tillitspost i Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "read error in `%s': %s\n"
+#, c-format
 msgid "read error in '%s': %s\n"
-msgstr "lesefeil ved «%s»: %s\n"
+msgstr "lesefeil i Â«%s»: %s\n"
 
 #, c-format
 msgid "trustdb: sync failed: %s\n"
-msgstr ""
+msgstr "trustdb: synk mislyktes. %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't create lock for `%s'\n"
+#, c-format
 msgid "can't create lock for '%s'\n"
-msgstr "kan ikke opprette lås for «%s»\n"
+msgstr "klarte ikke Ã¥ lage lÃ¥s for Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "can't lock `%s'\n"
+#, c-format
 msgid "can't lock '%s'\n"
-msgstr "kan ikke låse «%s»\n"
+msgstr "klarte ikke Ã¥ lÃ¥se Â«%s»\n"
 
 #, c-format
 msgid "trustdb rec %lu: lseek failed: %s\n"
-msgstr ""
+msgstr "trustdb-oppf. %lu: lseek mislyktes. %s\n"
 
 #, c-format
 msgid "trustdb rec %lu: write failed (n=%d): %s\n"
-msgstr ""
+msgstr "trustdb-oppf. %lu: skriving mislyktes (n=%d). %s\n"
 
 msgid "trustdb transaction too large\n"
-msgstr ""
+msgstr "trustdb-transaksjon er for stor\n"
 
 #, c-format
 msgid "%s: directory does not exist!\n"
-msgstr ""
+msgstr "%s: mappa finnes ikke.\n"
 
-#, fuzzy, c-format
-#| msgid "can't access `%s': %s\n"
+#, c-format
 msgid "can't access '%s': %s\n"
-msgstr "kan ikke aksere «%s»: %s\n"
+msgstr "fikk ikke tilgang til Â«%s»: %s\n"
 
 #, c-format
 msgid "%s: failed to create version record: %s"
-msgstr ""
+msgstr "%s: klarte ikke å lage versjonsoppføring. %s"
 
 #, c-format
 msgid "%s: invalid trustdb created\n"
-msgstr ""
+msgstr "%s: laget ugyldig trustdb\n"
 
 #, c-format
 msgid "%s: trustdb created\n"
-msgstr ""
+msgstr "%s: trustdb opprettet\n"
 
-#, fuzzy
 msgid "Note: trustdb not writable\n"
-msgstr "hemmelig nøkkel er ikke tilgjengelig"
+msgstr "Merk: trustdb er ikke skrivbar\n"
 
 #, c-format
 msgid "%s: invalid trustdb\n"
-msgstr ""
+msgstr "%s: ugyldig trustdb\n"
 
 #, c-format
 msgid "%s: failed to create hashtable: %s\n"
-msgstr ""
+msgstr "%s: klarte ikke å lage kontrollsum-tabell. %s\n"
 
 #, c-format
 msgid "%s: error updating version record: %s\n"
-msgstr ""
+msgstr "%s: feil under oppdatering av versjonsoppføring. %s\n"
 
 #, c-format
 msgid "%s: error reading version record: %s\n"
-msgstr ""
+msgstr "%s: feil under lesing av versjonsoppføring. %s\n"
 
 #, c-format
 msgid "%s: error writing version record: %s\n"
-msgstr ""
+msgstr "%s: feil under skriving av versjonsoppføring. %s\n"
 
 #, c-format
 msgid "trustdb: lseek failed: %s\n"
-msgstr ""
+msgstr "trustdb: lseek mislyktes. %s\n"
 
 #, c-format
 msgid "trustdb: read failed (n=%d): %s\n"
-msgstr ""
+msgstr "trustdb: lesing mislyktes (n=%d). %s\n"
 
 #, c-format
 msgid "%s: not a trustdb file\n"
-msgstr ""
+msgstr "%s: ikke en trustdb-fil\n"
 
 #, c-format
 msgid "%s: version record with recnum %lu\n"
-msgstr ""
+msgstr "%s: versjonsoppføring nr. %lu\n"
 
 #, c-format
 msgid "%s: invalid file version %d\n"
-msgstr ""
+msgstr "%s: %d er en ugyldig filversjon\n"
 
 #, c-format
 msgid "%s: error reading free record: %s\n"
-msgstr ""
+msgstr "%s: feil under lesing av «free»-oppføring. %s\n"
 
 #, c-format
 msgid "%s: error writing dir record: %s\n"
-msgstr ""
+msgstr "%s: feil under skriving av «dir»-oppføring. %s\n"
 
 #, c-format
 msgid "%s: failed to zero a record: %s\n"
-msgstr ""
+msgstr "%s: klarte ikke å nullstille oppføring. %s\n"
 
 #, c-format
 msgid "%s: failed to append a record: %s\n"
-msgstr ""
+msgstr "%s: klarte ikke å legge til oppføring. %s\n"
 
 msgid "Error: The trustdb is corrupted.\n"
-msgstr ""
+msgstr "Error: trustdb er skadet.\n"
 
 #, c-format
 msgid "can't handle text lines longer than %d characters\n"
-msgstr ""
+msgstr "tekstlinjer som er lengre enn %d tegn kan ikke behandles\n"
 
 #, c-format
 msgid "input line longer than %d characters\n"
-msgstr ""
+msgstr "inndata-linje er lengre enn %d tegn\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error beginning transaction on TOFU database: %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under transaksjonsstart i TOFU-database: %s\n"
 
 #, c-format
 msgid "error committing transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "feil under ferdigstillelse av transaksjon i TOFU-database: %s\n"
 
 #, c-format
 msgid "error rolling back transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "feil under reversering av transaksjon i TOFU-database: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unsupported TOFU database version: %s\n"
-msgstr ""
-"\n"
-"Støttede algoritmer:\n"
+msgstr "TOFU-databaseversjon støttes ikke: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading TOFU database: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av TOFU-database: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error writing secret keyring `%s': %s\n"
+#, c-format
 msgid "error determining TOFU database's version: %s\n"
-msgstr "feil ved skriving av hemmelig nøkkelknippe «%s»: %s\n"
+msgstr "klarte ikke å kontrollere versjon av TOFU-database: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error initializing TOFU database: %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under oppstart av TOFU-database: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error opening TOFU database '%s': %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under Ã¥pning av TOFU-database Â«%s»: %s\n"
 
 msgid "Warning: Home directory contains both tofu.db and tofu.d.\n"
-msgstr ""
+msgstr "Advarsel: Hjemmemappe inneholder både «tofu.db» og «tofu.d».\n"
 
 msgid "Using split format for TOFU database\n"
-msgstr ""
+msgstr "Bruker splittformat for TOFU-database\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error updating TOFU database: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under oppdatering av TOFU-database: %s\n"
 
 #, c-format
 msgid "The binding %s is NOT known."
-msgstr ""
+msgstr "Tilknytning %s er ukjent."
 
 #, c-format
 msgid ""
 "The key with fingerprint %s raised a conflict with the binding %s.  Since "
 "this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
+"Nøkkel med fingeravtrykk %s forårsaket konflikt med tilknytning %s. Siden "
+"regelen var «auto» er den nå endret til «ask» (spør)."
 
 #, c-format
 msgid ""
 "Please indicate whether you believe the binding %s%sis legitimate (the key "
 "belongs to the stated owner) or a forgery (bad)."
 msgstr ""
+"Oppgi hvorvidt du tror tilknytninga %s%ser sannferdig (dvs.: at nøkkelen "
+"tilhører personen som hevder å eie den) eller falsk."
 
-#, fuzzy, c-format
-#| msgid "error getting new PIN: %s\n"
+#, c-format
 msgid "error gathering other user IDs: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av andre bruker-id-er: %s\n"
 
 msgid "Known user IDs associated with this key:\n"
-msgstr ""
+msgstr "Kjente bruker-id-er tilknyttet denne nøkkelen:\n"
 
-#, fuzzy, c-format
-#| msgid "validity: %s"
+#, c-format
 msgid "policy: %s"
-msgstr "gyldighet: %s"
+msgstr "regelverk: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error gathering signature stats: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av signaturstatistikk: %s\n"
 
 #, c-format
 msgid "The email address \"%s\" is associated with %d key:\n"
 msgid_plural "The email address \"%s\" is associated with %d keys:\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "E-postadressen «%s» er tilknyttet %d nøkkel:\n"
+msgstr[1] "E-postadressen «%s» er tilknyttet %d nøkler:\n"
 
 #, c-format
 msgid "Statistics for keys with the email address \"%s\":\n"
-msgstr ""
+msgstr "Statistikk for nøkler med e-postadresse «%s»:\n"
 
-#, fuzzy
-#| msgid "list keys"
 msgid "this key"
-msgstr "liste nøkler"
+msgstr "denne nøkkelen"
 
 #, c-format
 msgid "%ld message signed in the future."
 msgid_plural "%ld messages signed in the future."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%ld melding signert i fremtid."
+msgstr[1] "%ld meldinger signert i fremtid."
 
-#, fuzzy, c-format
+#, c-format
 msgid "%ld message signed"
 msgid_plural "%ld messages signed"
-msgstr[0] "|algo [filer]|skrive meldingsdigester"
-msgstr[1] "|algo [filer]|skrive meldingsdigester"
+msgstr[0] "%ld melding signert"
+msgstr[1] "%ld meldinger signert"
 
 #, c-format
 msgid " over the past %ld day."
 msgid_plural " over the past %ld days."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] " i løpet av gårsdagen (%ld)."
+msgstr[1] " i løpet av de %ld siste dagene."
 
 #, c-format
 msgid " over the past %ld week."
 msgid_plural " over the past %ld weeks."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] " i løpet av den siste uka (%ld)."
+msgstr[1] " i løpet av de siste %ld ukene."
 
 #, c-format
 msgid " over the past %ld month."
 msgid_plural " over the past %ld months."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] " i løpet av den siste måneden (%ld)."
+msgstr[1] " i løpet av de siste %ld månedene."
 
 #. TRANSLATORS: Please translate the text found in the source
 #. * file below.  We don't directly internationalize that text so
 #. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
-msgstr ""
+msgstr "TOFU oppdaget en tilknytningskonflikt"
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
 #. * version of the hotkey) for each of the five choices.  If
 #. * there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
-msgstr ""
+msgstr "gGaAuUnNdD"
 
 msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
-msgstr ""
+msgstr "(G)od, (A)ksepter én gang, (U)kjent, (N)ekt én gang, (D)årlig? "
 
-#, fuzzy, c-format
+#, c-format
 msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under endring av tillitsnivå for TOFU-tilknytning til %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error changing TOFU policy: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under endring av TOFU-regler: %s\n"
 
 #. TRANSLATORS: The tilde ('~') is used here to indicate a
 #. * non-breakable space
 #, c-format
 msgid "%d~year"
 msgid_plural "%d~years"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d~år"
+msgstr[1] "%d~år"
 
 #, c-format
 msgid "%d~month"
 msgid_plural "%d~months"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d~måned"
+msgstr[1] "%d~måneder"
 
 #, c-format
 msgid "%d~day"
 msgid_plural "%d~days"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d~dag"
+msgstr[1] "%d~dager"
 
 #, c-format
 msgid "%d~hour"
 msgid_plural "%d~hours"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d~time"
+msgstr[1] "%d~timer"
 
 #, c-format
 msgid "%d~minute"
 msgid_plural "%d~minutes"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d~minutt"
+msgstr[1] "%d~minutter"
 
 #, c-format
 msgid "%d~second"
 msgid_plural "%d~seconds"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d~sekund"
+msgstr[1] "%d~sekunder"
 
 #, c-format
 msgid "Have never verified a message signed by key %s!\n"
-msgstr ""
+msgstr "Har aldri bekreftet en melding som er signert av nøkkel %s.\n"
 
 #, c-format
 msgid ""
 "Failed to collect signature statistics for \"%s\"\n"
 "(key %s)\n"
 msgstr ""
+"Klarte ikke å samle inn signaturstatistikk for «%s»\n"
+"(nøkkel %s)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Verified %ld messages signed by \"%s\"."
-msgstr "|algo [filer]|skrive meldingsdigester"
+msgstr "Bekreftet %ld meldinger signert av «%s»."
 
 #, c-format
 msgid ""
@@ -5767,17 +5593,24 @@ msgid_plural ""
 "Verified %ld messages signed by \"%s\"\n"
 "in the past %s."
 msgstr[0] ""
+"Bekreftet %ld melding signert av «%s»\n"
+"siste %s."
 msgstr[1] ""
+"Bekreftet %ld meldinger signert av «%s»\n"
+"siste %s."
 
 #, c-format
 msgid "The most recent message was verified %s ago."
-msgstr ""
+msgstr "Nyeste melding ble bekreftet for %s siden."
 
 msgid "Warning: we've have yet to see a message signed by this key!\n"
 msgstr ""
+"Advarsel: vi har enda ikke sett en melding som er signert av denne "
+"nøkkelen.\n"
 
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
+"Advarsel: vi har bare sett én melding som er signert av denne nøkkelen.\n"
 
 #, c-format
 msgid ""
@@ -5793,123 +5626,135 @@ msgid_plural ""
 "  %s\n"
 "to mark it as being bad.\n"
 msgstr[0] ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[1] ""
+"Advarsel: hvis du tror du har sett flere enn %ld meldinger som er signert av "
+"denne nøkkelen, kan det bety at den er forfalsket!  Undersøk e-postadressen "
+"nøye og se etter små variasjoner i navnet.\n"
+"Bruk %s \n"
+"for å markere nøkkelen som ugyldig hvis den virker mistenkelig.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error opening TOFU database: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under åpning av TOFU-database: %s\n"
 
-#, fuzzy, c-format
-#| msgid "`%s' is not a valid character set\n"
+#, c-format
 msgid "'%s' is not a valid long keyID\n"
-msgstr "«%s» er ikke et gyldig tegnsett\n"
+msgstr "«%s» er en ugyldig lang nøkkel-ID\n"
 
 #, c-format
 msgid "key %s: accepted as trusted key\n"
-msgstr "nøkkel %s: godtatt som betrodd nøkkel\n"
+msgstr "nøkkel %s: godtatt som betrodd nøkkel\n"
 
 #, c-format
 msgid "key %s occurs more than once in the trustdb\n"
-msgstr ""
+msgstr "nøkkel %s forekommer flere enn én gang i trustdb\n"
 
 #, c-format
 msgid "key %s: no public key for trusted key - skipped\n"
-msgstr "nøkkel %s: ingen offentlig nøkkel for betrodd nøkkel - hoppet over\n"
+msgstr "nøkkel %s: ingen offentlig nøkkel for betrodd nøkkel - hoppet over\n"
 
 #, c-format
 msgid "key %s marked as ultimately trusted\n"
-msgstr "nøkkel %s markert som endelig betrodd.\n"
+msgstr "nøkkel %s markert som endelig betrodd.\n"
 
 #, c-format
 msgid "trust record %lu, req type %d: read failed: %s\n"
-msgstr ""
+msgstr "tillitsoppføring %lu, foresp.type %d: lesing mislyktes. %s\n"
 
 #, c-format
 msgid "trust record %lu is not of requested type %d\n"
-msgstr ""
+msgstr "tillitsoppføring %lu er ikke av forespurt type (%d)\n"
 
 msgid "You may try to re-create the trustdb using the commands:\n"
 msgstr ""
+"Du kan prøve å gjenskape trustdb ved å skrive inn følgende kommandoer:\n"
 
 msgid "If that does not work, please consult the manual\n"
-msgstr ""
+msgstr "Se bruksanvisning hvis dette ikke hjelper\n"
 
 #, c-format
 msgid "unable to use unknown trust model (%d) - assuming %s trust model\n"
 msgstr ""
+"Klarte ikke å bruke ukjent tillitsmodell (%d). Prøver tillitsmodell %s\n"
 
 #, c-format
 msgid "using %s trust model\n"
-msgstr ""
+msgstr "bruker tillitsmodell %s\n"
 
 msgid "no need for a trustdb check\n"
-msgstr ""
+msgstr "kontroll av trustdb er ikke nødvendig\n"
 
 #, c-format
 msgid "next trustdb check due at %s\n"
-msgstr ""
+msgstr "neste kontroll av trustdb planlagt %s\n"
 
 #, c-format
 msgid "no need for a trustdb check with '%s' trust model\n"
-msgstr ""
+msgstr "trustdb behøver ikke kontroll ved bruk av tillitsmodell «%s»\n"
 
 #, c-format
 msgid "no need for a trustdb update with '%s' trust model\n"
-msgstr ""
+msgstr "trustdb behøver ikke oppdatering ved bruk av tillitsmodell «%s»\n"
 
 #, c-format
 msgid "public key %s not found: %s\n"
-msgstr "fant ikke offentlig nøkkel %s: %s\n"
+msgstr "fant ikke offentlig nøkkel %s: %s\n"
 
 msgid "please do a --check-trustdb\n"
-msgstr ""
+msgstr "kjør «--check-trustdb»\n"
 
 msgid "checking the trustdb\n"
-msgstr ""
+msgstr "kontrollerer trustdb\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys processed so far\n"
+#, c-format
 msgid "%d key processed"
 msgid_plural "%d keys processed"
-msgstr[0] "%lu nøkler behandlet hittil\n"
-msgstr[1] "%lu nøkler behandlet hittil\n"
+msgstr[0] "%d nøkkel behandlet"
+msgstr[1] "%d nøkler behandlet"
 
 #, c-format
 msgid " (%d validity count cleared)\n"
 msgid_plural " (%d validity counts cleared)\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "(%d gyldighetsantall klarert)\n"
+msgstr[1] "(%d gyldighetsantall klarert)\n"
 
 msgid "no ultimately trusted keys found\n"
-msgstr ""
+msgstr "fant ingen nøkler med absolutt («ultimat») pålitelighet\n"
 
 #, c-format
 msgid "public key of ultimately trusted key %s not found\n"
-msgstr ""
+msgstr "fant ikke offentlig nøkkel for absolutt pålitelig nøkkel %s\n"
 
 #, c-format
 msgid ""
 "depth: %d  valid: %3d  signed: %3d  trust: %d-, %dq, %dn, %dm, %df, %du\n"
 msgstr ""
+"dybde: %d  gyldig: %3d  signert: %3d  tillit: %d-, %dq, %dn, %dm, %df, %du\n"
 
 #, c-format
 msgid "unable to update trustdb version record: write failed: %s\n"
 msgstr ""
+"klarte ikke å oppdatere trustdb-versjonsoppføring. Skriving mislyktes. %s\n"
 
 msgid "undefined"
-msgstr ""
+msgstr "udefinert"
 
 msgid "never"
-msgstr ""
+msgstr "aldri"
 
 msgid "marginal"
-msgstr ""
+msgstr "marginal"
 
 msgid "full"
-msgstr ""
+msgstr "full"
 
 msgid "ultimate"
-msgstr ""
+msgstr "ultimat"
 
 #. TRANSLATORS: these strings are similar to those in
 #. trust_value_to_string(), but are a fixed length.  This is needed to
@@ -5920,154 +5765,153 @@ msgstr ""
 #. essentially a comment and need not be translated.  Either key and
 #. uid are both NULL, or neither are NULL.
 msgid "10 translator see trust.c:uid_trust_string_fixed"
-msgstr ""
+msgstr "11 translator see trustdb.c:uid_trust_string_fixed"
 
 msgid "[ revoked]"
 msgstr "[ opphevet]"
 
 msgid "[ expired]"
-msgstr "[ utgått]"
+msgstr "[   utgått]"
 
 msgid "[ unknown]"
-msgstr "[ ukjent]"
+msgstr "[   ukjent]"
 
 msgid "[  undef ]"
-msgstr "[ udef ]"
+msgstr "[    udef ]"
 
 msgid "[  never ]"
-msgstr ""
+msgstr "[   aldri ]"
 
 msgid "[marginal]"
-msgstr ""
+msgstr "[ marginal]"
 
 msgid "[  full  ]"
-msgstr ""
+msgstr "[   full  ]"
 
 msgid "[ultimate]"
-msgstr ""
+msgstr "[  fullst.]"
 
 msgid ""
 "the signature could not be verified.\n"
 "Please remember that the signature file (.sig or .asc)\n"
 "should be the first file given on the command line.\n"
 msgstr ""
+"klarte ikke å bekrefte signatur.\n"
+"Husk at signaturfil (.sig eller .asc)\n"
+"skal være første filargument på kommandolinja.\n"
 
 #, c-format
 msgid "input line %u too long or missing LF\n"
-msgstr ""
+msgstr "inndatalinje %u er for lang eller mangler LF\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't open fd %d: %s\n"
-msgstr "kan ikke åpne «%s»: %s\n"
+msgstr "klarte ikke å åpne fd %d: %s\n"
 
 msgid "set debugging flags"
-msgstr ""
+msgstr "endre feilsøkingsvalg"
 
 msgid "enable full debugging"
-msgstr ""
+msgstr "slå på full feilsøking"
 
-#, fuzzy
 msgid "Usage: kbxutil [options] [files] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: kbxutil [valg] [filer] (-h for hjelp)"
 
-#, fuzzy
 msgid ""
 "Syntax: kbxutil [options] [files]\n"
 "List, export, import Keybox data\n"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr ""
+"Syntaks: kbxutil [valg] [filer]\n"
+"Vis, eksporter eller importer Keybox-data\n"
 
 #, c-format
 msgid "RSA modulus missing or not of size %d bits\n"
-msgstr "RSA-modulus mangler eller har ikke en størrelse på %d bits\n"
+msgstr "RSA-modulus mangler eller er av annen størrelse enn %d bit\n"
 
 #, c-format
 msgid "RSA public exponent missing or larger than %d bits\n"
-msgstr "offentlig RSA-eksponent mangler eller er større enn %d bits\n"
+msgstr "offentlig RSA-eksponent mangler eller er større enn %d bit\n"
 
 #, c-format
 msgid "PIN callback returned error: %s\n"
 msgstr "PIN-callback returnerte en feil: %s\n"
 
 msgid "the NullPIN has not yet been changed\n"
-msgstr ""
+msgstr "NullPIN er ikke blitt endret enda\n"
 
-#, fuzzy
 msgid "|N|Please enter a new PIN for the standard keys."
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "|N|Skriv inn ny PIN-kode for standardnøkler."
 
-#, fuzzy
 msgid "||Please enter the PIN for the standard keys."
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "||Skriv inn PIN-kode for standardnøkler."
 
-#, fuzzy
 msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys."
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "|NP|Skriv inn ny PIN-opplåsingskode (PUK) for standardnøkler."
 
-#, fuzzy
 msgid "|P|Please enter the PIN Unblocking Code (PUK) for the standard keys."
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "|P|Skriv inn PIN-opplåsingskode (PUK) for standardnøkler."
 
 msgid "|N|Please enter a new PIN for the key to create qualified signatures."
-msgstr ""
+msgstr "|N|Skriv inn ny PIN for å la nøkkelen lage kvalifiserte signaturer."
 
 msgid "||Please enter the PIN for the key to create qualified signatures."
-msgstr ""
+msgstr "||Skriv inn PIN for å la nøkkelen lage kvalifiserte signaturer."
 
 msgid ""
 "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
 msgstr ""
+"|NP|Skriv inn ny PUK-kode for å la nøkkelen lage kvalifiserte signaturer."
 
 msgid ""
 "|P|Please enter the PIN Unblocking Code (PUK) for the key to create "
 "qualified signatures."
-msgstr ""
+msgstr "|P|Skriv inn PUK-kode for å la nøkkelen lage kvalifiserte signaturer."
 
 #, c-format
 msgid "error getting new PIN: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av ny PIN: %s\n"
 
 #, c-format
 msgid "failed to store the fingerprint: %s\n"
-msgstr "klarte ikke å lagre fingeravtrykket: %s\n"
+msgstr "klarte ikke å lagre fingeravtrykk: %s\n"
 
 #, c-format
 msgid "failed to store the creation date: %s\n"
-msgstr "klarte ikke å lagre opprettelsesdatoen: %s\n"
+msgstr "klarte ikke å lagre opprettelsesdato: %s\n"
 
 #, c-format
 msgid "reading public key failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
 
 msgid "response does not contain the public key data\n"
-msgstr "respons inneholder ikke data om offentlig nøkkel\n"
+msgstr "svar inneholder ikke offentlig nøkkeldata\n"
 
 msgid "response does not contain the RSA modulus\n"
-msgstr "respons inneholder ikke RSA-modulus\n"
+msgstr "svar inneholder ikke RSA-modulus\n"
 
 msgid "response does not contain the RSA public exponent\n"
-msgstr "respons inneholder ikke den offentlige RSA-eksponenten\n"
+msgstr "svar inneholder ikke offentlig RSA-eksponent\n"
 
-#, fuzzy
-#| msgid "response does not contain the RSA public exponent\n"
 msgid "response does not contain the EC public point\n"
-msgstr "respons inneholder ikke den offentlige RSA-eksponenten\n"
+msgstr "svar inneholder ikke offentlig EC-punkt\n"
 
 #, c-format
 msgid "using default PIN as %s\n"
-msgstr ""
+msgstr "bruker forvalgt PIN som %s\n"
 
 #, c-format
 msgid "failed to use default PIN as %s: %s - disabling further default use\n"
 msgstr ""
+"klarte ikke å bruke forvalgt PIN som %s. %s. Lar være å bruke forvalgt PIN "
+"senere\n"
 
 #, c-format
 msgid "||Please enter the PIN%%0A[sigs done: %lu]"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "||Skriv inn PIN%%0A[signaturer utført: %lu]"
 
-#, fuzzy
 msgid "||Please enter the PIN"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "||Skriv inn PIN-kode"
 
 #, c-format
 msgid "PIN for CHV%d is too short; minimum length is %d\n"
@@ -6078,45 +5922,42 @@ msgid "verify CHV%d failed: %s\n"
 msgstr "bekreftelse av CHV%d mislyktes: %s\n"
 
 msgid "error retrieving CHV status from card\n"
-msgstr "feil ved henting av CHV-status fra kort\n"
+msgstr "feil under henting av CHV-status fra kort\n"
 
 msgid "card is permanently locked!\n"
-msgstr "kort er permanent låst!\n"
+msgstr "kortet er låst for godt.\n"
 
-#, fuzzy, c-format
-#| msgid "%d Admin PIN attempts remaining before card is permanently locked\n"
+#, c-format
 msgid "%d Admin PIN attempt remaining before card is permanently locked\n"
 msgid_plural ""
 "%d Admin PIN attempts remaining before card is permanently locked\n"
-msgstr[0] "%d Admin PIN-forsøk før kortet blir låst permanent\n"
-msgstr[1] "%d Admin PIN-forsøk før kortet blir låst permanent\n"
+msgstr[0] "%d Admin-PIN-forsøk gjenstår før kortet blir låst permanent\n"
+msgstr[1] "%d Admin-PIN-forsøk gjenstår før kortet blir låst permanent\n"
 
 #. TRANSLATORS: Do not translate the "|A|" prefix but keep it at
 #. the start of the string.  Use %%0A to force a linefeed.
-#, fuzzy, c-format
+#, c-format
 msgid "|A|Please enter the Admin PIN%%0A[remaining attempts: %d]"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "|A|Skriv inn admin-PIN%%0A[gjenstående forsøk: %d]"
 
-#, fuzzy
 msgid "|A|Please enter the Admin PIN"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "|A|Skriv inn admin-PIN"
 
 msgid "access to admin commands is not configured\n"
 msgstr "tilgang til admin-kommandoer er ikke konfigurert\n"
 
-#, fuzzy
 msgid "||Please enter the Reset Code for the card"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "||Skriv inn tilbakestillingskode for kortet"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Reset Code is too short; minimum length is %d\n"
-msgstr "PIN for CHV%d er for kort; minum lengde er %d\n"
+msgstr "Tilbakestillingskoden er for kort. Minimumslengde er %d\n"
 
 #. TRANSLATORS: Do not translate the "|*|" prefixes but
 #. keep it at the start of the string.  We need this elsewhere
 #. to get some infos on the string.
 msgid "|RN|New Reset Code"
-msgstr ""
+msgstr "|RN|Ny tilbakestillingskode"
 
 msgid "|AN|New Admin PIN"
 msgstr "|AN|Ny Admin PIN"
@@ -6124,375 +5965,347 @@ msgstr "|AN|Ny Admin PIN"
 msgid "|N|New PIN"
 msgstr "|N|Ny PIN"
 
-#, fuzzy
 msgid "||Please enter the Admin PIN and New Admin PIN"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "||Skriv inn admin-PIN og ny admin-PIN"
 
-#, fuzzy
 msgid "||Please enter the PIN and New PIN"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "||Skriv inn PIN-kode og ny PIN-kode"
 
 msgid "error reading application data\n"
-msgstr "feil ved lesing av applikasjonsdata\n"
+msgstr "feil under lesing av programdata\n"
 
 msgid "error reading fingerprint DO\n"
-msgstr "feil ved lesing av fingeravtrykk DO\n"
+msgstr "feil under lesing av fingeravtrykk DO\n"
 
 msgid "key already exists\n"
-msgstr "nøkkel finnes allerede\n"
+msgstr "nøkkelen finnes allerede\n"
 
 msgid "existing key will be replaced\n"
-msgstr "eksisterende nøkkel vil bli erstattet\n"
+msgstr "gjeldende nøkkel blir erstattet\n"
 
 msgid "generating new key\n"
-msgstr "generere en ny nøkkel\n"
+msgstr "lager ny nøkkel\n"
 
-#, fuzzy
 msgid "writing new key\n"
-msgstr "generere en ny nøkkel\n"
+msgstr "skriver ny nøkkel\n"
 
 msgid "creation timestamp missing\n"
 msgstr "tidsstempel for opprettelse mangler\n"
 
 #, c-format
 msgid "RSA prime %s missing or not of size %d bits\n"
-msgstr "RSA-primtall %s mangler eller har ikke en størrelse på %d bits\n"
+msgstr "RSA-primtall %s mangler eller er av annen størrelse enn %d bit\n"
 
 #, c-format
 msgid "failed to store the key: %s\n"
-msgstr "klarte ikke å lagre nøkkelen: %s\n"
+msgstr "klarte ikke å lagre nøkkel. %s\n"
 
-#, fuzzy
-#| msgid "unsupported URI"
 msgid "unsupported curve\n"
-msgstr "ustøttet URI"
+msgstr "ustøttet kurve\n"
 
 msgid "please wait while key is being generated ...\n"
-msgstr "vennligst vent mens nøkkel blir generert ...\n"
+msgstr "vent mens nøkkel blir generert …\n"
 
 msgid "generating key failed\n"
-msgstr "nøkkelgenerering mislyktes\n"
+msgstr "nøkkelgenerering mislyktes\n"
 
-#, fuzzy, c-format
-#| msgid "key generation completed (%d seconds)\n"
+#, c-format
 msgid "key generation completed (%d second)\n"
 msgid_plural "key generation completed (%d seconds)\n"
-msgstr[0] "nøkkelgenerering fullført (%d sekunder)\n"
-msgstr[1] "nøkkelgenerering fullført (%d sekunder)\n"
+msgstr[0] "nøkkelgenerering fullført (%d sekund)\n"
+msgstr[1] "nøkkelgenerering fullført (%d sekunder)\n"
 
 msgid "invalid structure of OpenPGP card (DO 0x93)\n"
 msgstr "ugyldig struktur i OpenPGP-kort (DO 0x93)\n"
 
 msgid "fingerprint on card does not match requested one\n"
-msgstr ""
+msgstr "fingeravtrykk på kort samsvarer ikke med forespurt avtrykk\n"
 
 #, c-format
 msgid "card does not support digest algorithm %s\n"
-msgstr "kortet støtter ikke digestalgoritme %s\n"
+msgstr "kortet støtter ikke kontrollsum-algoritme %s\n"
 
 #, c-format
 msgid "signatures created so far: %lu\n"
-msgstr "signaturer opprettet så langt: %lu\n"
+msgstr "signaturer opprettet så langt: %lu\n"
 
 msgid ""
 "verification of Admin PIN is currently prohibited through this command\n"
-msgstr "bekrefting av Admin PIN er foreløpig nektet gjennom denne kommandoen\n"
+msgstr "bekrefting av Admin PIN er foreløpig nektet gjennom denne kommandoen\n"
 
 #, c-format
 msgid "can't access %s - invalid OpenPGP card?\n"
-msgstr "kan ikke aksere %s - ugyldig OpenPGP-kort?\n"
+msgstr "fikk ikke tilgang til %s. Bruker du et ugyldig OpenPGP-kort?\n"
 
-#, fuzzy
 msgid "||Please enter your PIN at the reader's pinpad"
-msgstr "||Vennligst tast inn PIN%%0A[signaturer utført: %lu]"
+msgstr "||Skriv inn PIN-koden på leserens kodetastatur"
 
 #. TRANSLATORS: Do not translate the "|*|" prefixes but
 #. keep it at the start of the string.  We need this elsewhere
 #. to get some infos on the string.
-#, fuzzy
 msgid "|N|Initial New PIN"
 msgstr "|N|Ny PIN"
 
 msgid "run in multi server mode (foreground)"
-msgstr ""
+msgstr "kjør i multi-tjenermodus (forgrunn)"
 
 msgid "|LEVEL|set the debugging level to LEVEL"
-msgstr ""
+msgstr "|NIVÅ|endre feilsøkingsnivå til valgt NIVÅ"
 
-#, fuzzy
 msgid "|FILE|write a log to FILE"
-msgstr "leser valg fra «%s»\n"
+msgstr "|FIL|skriv logg til valgt FIL"
 
 msgid "|N|connect to reader at port N"
-msgstr ""
+msgstr "|N|koble til leser via port N"
 
 msgid "|NAME|use NAME as ct-API driver"
-msgstr ""
+msgstr "|NAVN|bruk valgt NAVN som ct-API-driver"
 
 msgid "|NAME|use NAME as PC/SC driver"
-msgstr ""
+msgstr "|NAME|bruk valgt NAVN som PC-/SC-driver"
 
 msgid "do not use the internal CCID driver"
-msgstr ""
+msgstr "ikke bruk intern CCID-driver"
 
 msgid "|N|disconnect the card after N seconds of inactivity"
-msgstr ""
+msgstr "|N|koble fra kort etter N antall sekunder uten aktivitet"
 
 msgid "do not use a reader's pinpad"
-msgstr ""
+msgstr "ikke bruk kodetastatur"
 
-#, fuzzy
 msgid "deny the use of admin card commands"
-msgstr "vise admin-kommandoer"
+msgstr "avvis bruk av admin-kortkommandoer"
 
 msgid "use variable length input for pinpad"
-msgstr ""
+msgstr "bruk inndata av vairabel lengde for kodetastatur"
 
-#, fuzzy
 msgid "Usage: @SCDAEMON@ [options] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: @SCDAEMON@ [valg] (-h for hjelp)"
 
 msgid ""
 "Syntax: scdaemon [options] [command [args]]\n"
 "Smartcard daemon for @GNUPG@\n"
 msgstr ""
+"Syntaks: scdaemon [valg] [kommando [arg]]\n"
+"Smartcard-bakgrunnsprogram for @GNUPG@\n"
 
 msgid "please use the option '--daemon' to run the program in the background\n"
-msgstr ""
+msgstr "bruk valget «--daemon» for å kjøre programmet i bakgrunnen\n"
 
 #, c-format
 msgid "handler for fd %d started\n"
-msgstr ""
+msgstr "startet håndteringsprogram for fd %d\n"
 
 #, c-format
 msgid "handler for fd %d terminated\n"
-msgstr ""
+msgstr "avsluttet håndteringsprogram for fd %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid radix64 character %02x skipped\n"
 msgstr "hoppet over ugyldig radix64-tegn %02x\n"
 
 msgid "no dirmngr running in this session\n"
-msgstr ""
+msgstr "ingen dirmngr kjører i gjeldende økt\n"
 
 #, c-format
 msgid "validation model requested by certificate: %s"
-msgstr ""
+msgstr "kontrollmodell forespurt av sertifikat: %s"
 
 msgid "chain"
-msgstr ""
+msgstr "kjede"
 
 msgid "shell"
-msgstr ""
+msgstr "skall"
 
 #, c-format
 msgid "critical certificate extension %s is not supported"
-msgstr ""
+msgstr "kritisk sertifikatutvidelse %s støttes ikke"
 
 msgid "issuer certificate is not marked as a CA"
-msgstr ""
+msgstr "utsteders sertifikat er ikke merket som CA"
 
 msgid "critical marked policy without configured policies"
-msgstr ""
+msgstr "regelsett merket som kritisk uten oppsatte regler"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to open '%s': %s\n"
-msgstr "Kan ikke åpne «%s»: %s\n"
+msgstr "klarte ikke Ã¥ Ã¥pne Â«%s»: %s\n"
 
-#, fuzzy
 msgid "Note: non-critical certificate policy not allowed"
-msgstr "eksportering av hemmelige nøkler er ikke tillatt\n"
+msgstr "Merk: ukritisk sertifikat-regelsett er ikke tillatt"
 
-#, fuzzy
 msgid "certificate policy not allowed"
-msgstr "eksportering av hemmelige nøkler er ikke tillatt\n"
+msgstr "sertifikatregelverk tillates ikke"
 
 msgid "looking up issuer at external location\n"
-msgstr ""
+msgstr "slår opp utsteder på ekstern plassering\n"
 
 #, c-format
 msgid "number of issuers matching: %d\n"
-msgstr ""
+msgstr "antall ustedere funnet: %d\n"
 
 msgid "looking up issuer from the Dirmngr cache\n"
-msgstr ""
+msgstr "slår opp utsteder fra Dirmngr-hurtiglager\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "number of matching certificates: %d\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "antall treff på sertifikater: %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "dirmngr cache-only key lookup failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "nøkkeloppslag i dirmngr-hurtiglager mislyktes: %s\n"
 
-#, fuzzy
 msgid "failed to allocate keyDB handle\n"
-msgstr "klarte ikke å lagre nøkkelen: %s\n"
+msgstr "klarte ikke å tildele nøkkeldatabase-verdi\n"
 
 msgid "certificate has been revoked"
-msgstr ""
+msgstr "sertifikatet er opphevet"
 
 msgid "the status of the certificate is unknown"
-msgstr ""
+msgstr "sertifikatet har ukjent status"
 
 msgid "please make sure that the \"dirmngr\" is properly installed\n"
-msgstr ""
+msgstr "kontroller at «dirmngr» er installert skikkelig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "checking the CRL failed: %s"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "kontroll av CRL mislyktes: %s"
 
 #, c-format
 msgid "certificate with invalid validity: %s"
-msgstr ""
+msgstr "sertifikat med ugyldig gyldighetsverdi: %s"
 
 msgid "certificate not yet valid"
-msgstr ""
+msgstr "sertifikatet er ikke gyldig enda"
 
-#, fuzzy
 msgid "root certificate not yet valid"
-msgstr "eksportering av hemmelige nøkler er ikke tillatt\n"
+msgstr "rotsertifikat er ikke gyldig enda"
 
 msgid "intermediate certificate not yet valid"
-msgstr ""
+msgstr "mellomsertifikat er ikke gyldig enda"
 
-#, fuzzy
 msgid "certificate has expired"
-msgstr "Denne nøkkelen er utgått!"
+msgstr "sertifikatet er utgått"
 
-#, fuzzy
 msgid "root certificate has expired"
-msgstr "Denne nøkkelen er utgått!"
+msgstr "rotsertifikat er utgått"
 
-#, fuzzy
 msgid "intermediate certificate has expired"
-msgstr "Denne nøkkelen er utgått!"
+msgstr "mellomsertifikat er utgått"
 
 #, c-format
 msgid "required certificate attributes missing: %s%s%s"
-msgstr ""
+msgstr "påkrevde sertifikategenskaper mangler: %s%s%s"
 
-#, fuzzy
 msgid "certificate with invalid validity"
-msgstr "Denne nøkkelen er utgått!"
+msgstr "sertifikat med ugyldig gyldighetsverdi"
 
 msgid "signature not created during lifetime of certificate"
-msgstr ""
+msgstr "signatur ikke laget innenfor sertifikatets levetid"
 
 msgid "certificate not created during lifetime of issuer"
-msgstr ""
+msgstr "sertifikat ikke laget innenfor utsteders levetid"
 
 msgid "intermediate certificate not created during lifetime of issuer"
-msgstr ""
+msgstr "mellomsertifikat ikke laget innenfor utsteders levetid"
 
-#, fuzzy
 msgid "  (  signature created at "
-msgstr "         oppryddete signaturer: %lu\n"
+msgstr "  (  signatur opprettet "
 
-#, fuzzy
 msgid "  (certificate created at "
-msgstr "preferansen %s er duplisert\n"
+msgstr "  (sertifikat opprettet "
 
-#, fuzzy
 msgid "  (certificate valid from "
-msgstr "ugyldig sertifikat"
+msgstr "  (sertifikat gyldig fra "
 
-#, fuzzy
 msgid "  (     issuer valid from "
-msgstr "      Serienummer for kort ="
+msgstr "  (     utsteder gyldig fra "
 
-#, fuzzy, c-format
+#, c-format
 msgid "fingerprint=%s\n"
-msgstr "CA-fingeravtrykk: "
+msgstr "fingeravtrykk=%s\n"
 
 msgid "root certificate has now been marked as trusted\n"
-msgstr ""
+msgstr "rotsertifikat er nå merket som troverdig\n"
 
 msgid "interactive marking as trusted not enabled in gpg-agent\n"
-msgstr ""
+msgstr "interaktiv tillitsmerking er ikke slått på i gpg-agent\n"
 
 msgid "interactive marking as trusted disabled for this session\n"
-msgstr ""
+msgstr "interaktiv tillitsmarkering er slått av for gjeldende økt\n"
 
 msgid "WARNING: creation time of signature not known - assuming current time"
 msgstr ""
+"ADVARSEL: opprettelsestid for signatur er ukjent. Antar gjeldende tidspunkt"
 
-#, fuzzy
 msgid "no issuer found in certificate"
-msgstr "generere et opphevingssertifikat"
+msgstr "fant ingen utsteder i sertifikat"
 
 msgid "self-signed certificate has a BAD signature"
-msgstr ""
+msgstr "selvsignert sertifikat har ugyldig signatur"
 
 msgid "root certificate is not marked trusted"
-msgstr ""
+msgstr "rotsertifikat er ikke merket som troverdig"
 
-#, fuzzy, c-format
+#, c-format
 msgid "checking the trust list failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "kontroll av tillitsliste mislyktes: %s\n"
 
 msgid "certificate chain too long\n"
-msgstr ""
+msgstr "sertifikatkjede er for langt\n"
 
 msgid "issuer certificate not found"
-msgstr ""
+msgstr "fant ikke utstedersertifikat"
 
-#, fuzzy
 msgid "certificate has a BAD signature"
-msgstr "bekrefte en signatur"
+msgstr "sertifikatet har ugyldig signatur"
 
 msgid "found another possible matching CA certificate - trying again"
-msgstr ""
+msgstr "fant et annet CA-sertifikat som kan fungere. Prøver igjen"
 
 #, c-format
 msgid "certificate chain longer than allowed by CA (%d)"
-msgstr ""
+msgstr "sertifikatkjede er lengre enn CA tillater (%d)"
 
-#, fuzzy
 msgid "certificate is good\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "sertifikatet er gyldig\n"
 
-#, fuzzy
 msgid "intermediate certificate is good\n"
-msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - avvist\n"
+msgstr "mellomsertifikat er ok\n"
 
-#, fuzzy
 msgid "root certificate is good\n"
-msgstr "ugyldig sertifikat"
+msgstr "rotsertifikat er gyldig\n"
 
 msgid "switching to chain model"
-msgstr ""
+msgstr "bytter til kjedemodell"
 
 #, c-format
 msgid "validation model used: %s"
-msgstr ""
+msgstr "gyldighetsmodell: %s"
 
 #, c-format
 msgid "a %u bit hash is not valid for a %u bit %s key\n"
-msgstr ""
+msgstr "kontrollsum på %u bit er ugyldig for en %u-bit %s-nøkkel\n"
 
 msgid "(this is the MD2 algorithm)\n"
-msgstr ""
+msgstr "(dette er algortime MD2)\n"
 
-#, fuzzy
 msgid "none"
-msgstr "nei"
+msgstr "ingen"
 
-#, fuzzy
 msgid "[Error - invalid encoding]"
-msgstr "Feil: ugyldig respons.\n"
+msgstr "[Feil - utgyldig koding]"
 
 msgid "[Error - out of core]"
-msgstr ""
+msgstr "[feil - kjernen er full]"
 
 msgid "[Error - No name]"
-msgstr ""
+msgstr "[feil - ingen navn]"
 
-#, fuzzy
 msgid "[Error - invalid DN]"
-msgstr "Feil: ugyldig respons.\n"
+msgstr "[feil - ugyldig DN]"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Please enter the passphrase to unlock the secret key for the X.509 "
 "certificate:\n"
@@ -6500,459 +6313,436 @@ msgid ""
 "S/N %s, ID 0x%08lX,\n"
 "created %s, expires %s.\n"
 msgstr ""
-"Du trenger en passfrase for å låse opp den hemmelige nøkkelen for brukeren:\n"
-"«%.*s»\n"
-"%u-bit %s nøkkel, ID %s, opprettet %s%s\n"
+"Skriv inn passordfrase for å låse opp hemmelig nøkkel til følgende X.509-"
+"sertifikat:\n"
+"«%s»\n"
+"S/N %s, ID 0x%08lX,\n"
+"opprettet %s, utgår %s.\n"
 
 msgid "no key usage specified - assuming all usages\n"
-msgstr ""
+msgstr "ingen bruksområder for nøkler valgt. Antar alle bruksområder\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting key usage information: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under henting av informasjon om nøkkelbruk: %s\n"
 
 msgid "certificate should not have been used for certification\n"
-msgstr ""
+msgstr "sertifikatet skulle ikke vært brukt til sertifisering\n"
 
 msgid "certificate should not have been used for OCSP response signing\n"
-msgstr ""
+msgstr "sertifikatet skulle ikke vært brukt til OCSP-responssignering\n"
 
 msgid "certificate should not have been used for encryption\n"
-msgstr ""
+msgstr "sertifikatet skulle ikke vært brukt til kryptering\n"
 
 msgid "certificate should not have been used for signing\n"
-msgstr ""
+msgstr "sertifikatet skulle ikke vært brukt til signering\n"
 
 msgid "certificate is not usable for encryption\n"
-msgstr ""
+msgstr "sertifikatet egner seg ikke til kryptering\n"
 
 msgid "certificate is not usable for signing\n"
-msgstr ""
+msgstr "sertifikatet egner seg ikke til signering\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid algorithm\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: ugyldig algoritme\n"
 
 #, c-format
 msgid "line %d: invalid key length %u (valid are %d to %d)\n"
-msgstr ""
+msgstr "linje %d: nøkkellengden %u er ugyldig (skal være mellom %d og %d)\n"
 
 #, c-format
 msgid "line %d: no subject name given\n"
-msgstr ""
+msgstr "linje %d: emnenavn mangler\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid subject name label '%.*s'\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: emne-etikett«%.*s» er ugyldig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid subject name '%s' at pos %d\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: emnenavn «%s» ved posisjon %d er ugyldig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: not a valid email address\n"
-msgstr "Ikke en gyldig epostadresse\n"
+msgstr "linje %d: ugyldig e-postadresse\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid serial number\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: ugyldig serienummer\n"
 
 #, c-format
 msgid "line %d: invalid issuer name label '%.*s'\n"
-msgstr ""
+msgstr "linje %d: utsteder-etikett «%.*s» er ugyldig\n"
 
 #, c-format
 msgid "line %d: invalid issuer name '%s' at pos %d\n"
-msgstr ""
+msgstr "linje %d: utstedernavn «%s» ved posisjon %d er ugyldig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid date given\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: ugyldig dato\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: error getting signing key by keygrip '%s': %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr ""
+"linje %d: feil under henting av signeringsnøkkel ved nøkkelgrep «%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid hash algorithm given\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: ugyldig summeringsalgoritme\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid authority-key-id\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: ugyldig Â«authority-key-id»\n"
 
-#, fuzzy, c-format
-#| msgid "key %s: invalid subkey binding\n"
+#, c-format
 msgid "line %d: invalid subject-key-id\n"
-msgstr "nøkkel %s: ugyldig undernøkkelbinding\n"
+msgstr "linje %d: ugyldig «subject-key-id»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: invalid extension syntax\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "linje %d: ugyldig utvidelsessyntaks\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: error reading key '%s' from card: %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "linje %d: fiel under lesing av nøkkel «%s» fra kort: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: error getting key by keygrip '%s': %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "linje %d: feil under henting av nøkkel av nøkkelgrep Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "line %d: key generation failed: %s <%s>\n"
-msgstr "Nøkkelgenerering mislyktes: %s\n"
+msgstr "linje %d: nøkkelgenerering mislyktes: %s <%s>\n"
 
 msgid ""
 "To complete this certificate request please enter the passphrase for the key "
 "you just created once more.\n"
 msgstr ""
+"Skriv inn passordfrasen for nøkkelen én gang til for å fullføre denne "
+"sertifikat-forespørselen.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) RSA\n"
-msgstr "   (%d) RSA (bare signering)\n"
+msgstr "   (%d) RSA\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) Existing key\n"
-msgstr "   (2) Krypteringsnøkkel\n"
+msgstr "   (%d) Nøkkel\n"
 
 #, c-format
 msgid "   (%d) Existing key from card\n"
-msgstr ""
+msgstr "   (%d) Nøkkel fra kort\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading the card: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av kort: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Serial number of the card: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "Kortets serienummer: %s\n"
 
-#, fuzzy
 msgid "Available keys:\n"
-msgstr "utkoble en nøkkel"
+msgstr "Tilgjengelige nøkler:\n"
 
 #, c-format
 msgid "Possible actions for a %s key:\n"
-msgstr ""
+msgstr "Mulige handlinger for %s-nøkler:\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) sign, encrypt\n"
-msgstr "   (%d) DSA (bare signering)\n"
+msgstr "   (%d) signer, krypter\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) sign\n"
-msgstr "   (%d) DSA (bare signering)\n"
+msgstr "   (%d) signer\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "   (%d) encrypt\n"
-msgstr "   (%d) RSA (bare kryptering)\n"
+msgstr "   (%d) krypter\n"
 
 msgid "Enter the X.509 subject name: "
-msgstr ""
+msgstr "Skriv inn X.509-emnenavn: "
 
 msgid "No subject name given\n"
-msgstr ""
+msgstr "Ingen emnenavn oppgitt\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Invalid subject name label '%.*s'\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "Emneetikett «%.*s» er ugyldig\n"
 
 #. TRANSLATORS: The 22 in the second string is the
 #. length of the first string up to the "%s".  Please
 #. adjust it do the length of your translation.  The
 #. second string is merely passed to atoi so you can
 #. drop everything after the number.
-#, fuzzy, c-format
+#, c-format
 msgid "Invalid subject name '%s'\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "Emnenavnet «%s» er ugyldig\n"
 
 msgid "22 translator: see certreg-ui.c:gpgsm_gencertreq_tty"
-msgstr ""
+msgstr "12"
 
-#, fuzzy
 msgid "Enter email addresses"
-msgstr "Epostadresse: "
+msgstr "Skriv inn e-postadresser"
 
-#, fuzzy
 msgid " (end with an empty line):\n"
-msgstr ""
-"\n"
-"Tast inn brukeriden.  Avslutt med en blank linje: "
+msgstr " (avslutt med tom linje):\n"
 
-#, fuzzy
 msgid "Enter DNS names"
-msgstr "Tast inn nytt filnavn"
+msgstr "Skriv inn DNS-navn"
 
-#, fuzzy
 msgid " (optional; end with an empty line):\n"
-msgstr ""
-"\n"
-"Tast inn brukeriden.  Avslutt med en blank linje: "
+msgstr " (valgfritt. Avslutt med tom linje):\n"
 
-#, fuzzy
 msgid "Enter URIs"
-msgstr "Tast inn PIN: "
+msgstr "Skriv inn adresser"
 
-#, fuzzy
-#| msgid "Create a designated revocation certificate for this key? (y/N) "
 msgid "Create self-signed certificate? (y/N) "
-msgstr "Lage et utpekt opphevingssertifikat for denne nøkkelen? (j/N) "
+msgstr "Vil du lage selvsignert sertifikat? (y/N) "
 
 msgid "These parameters are used:\n"
-msgstr ""
+msgstr "Følgende parametre brukes:\n"
 
 msgid "Now creating self-signed certificate.  "
-msgstr ""
+msgstr "Lager selvsignert sertifikat."
 
-#, fuzzy
 msgid "Now creating certificate request.  "
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "Lager sertifikatforespørsel.  "
 
 msgid "This may take a while ...\n"
-msgstr ""
+msgstr "Dette kan ta en stund …\n"
 
 msgid "Ready.\n"
-msgstr ""
+msgstr "Ferdig.\n"
 
 msgid "Ready.  You should now send this request to your CA.\n"
 msgstr ""
+"Ferdig. Du kan nå sende denne forespørselen til aktuell sertifikatutsteder "
+"(CA).\n"
 
 msgid "resource problem: out of core\n"
-msgstr ""
+msgstr "ressursproblem: oppbrukt kjerne\n"
 
 msgid "(this is the RC2 algorithm)\n"
-msgstr ""
+msgstr "(dette er algoritme RC2)\n"
 
 msgid "(this does not seem to be an encrypted message)\n"
-msgstr ""
+msgstr "(dette ser ikke ut som en kryptert melding)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "certificate '%s' not found: %s\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "fant ikke sertifikatet «%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error locking keybox: %s\n"
-msgstr "feil ved lesing av nøkkelblokk: %s\n"
+msgstr "feil under låsing av nøkkelskrin: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "duplicated certificate '%s' deleted\n"
-msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - avvist\n"
+msgstr "duplikatsertifikat «%s» slettet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "certificate '%s' deleted\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "sertifikat «%s» slettet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "deleting certificate \"%s\" failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "sletting av sertifikat «%s» mislyktes: %s\n"
 
-#, fuzzy
 msgid "no valid recipients given\n"
-msgstr "ingen gyldige adressater\n"
+msgstr "ingen gyldige mottakere valgt\n"
 
-#, fuzzy
 msgid "list external keys"
-msgstr "liste hemmelige nøkler"
+msgstr "vis eksterne nøkler"
 
-#, fuzzy
 msgid "list certificate chain"
-msgstr "ugyldig sertifikat"
+msgstr "vis sertifikatkjede "
 
-#, fuzzy
 msgid "import certificates"
-msgstr "ugyldig sertifikat"
+msgstr "importer sertifikater"
 
-#, fuzzy
 msgid "export certificates"
-msgstr "ugyldig sertifikat"
+msgstr "eksporter sertifikater"
 
 msgid "register a smartcard"
-msgstr ""
+msgstr "registrer smartkort"
 
 msgid "pass a command to the dirmngr"
-msgstr ""
+msgstr "send en kommando til dirmngr"
 
 msgid "invoke gpg-protect-tool"
-msgstr ""
+msgstr "kall gpg-protect-tool"
 
-#, fuzzy
 msgid "create base-64 encoded output"
-msgstr "lage ASCII-beskyttet output"
+msgstr "lag base64-kodet utdata"
 
 msgid "assume input is in PEM format"
-msgstr ""
+msgstr "forvent inndata i «PEM»-format"
 
 msgid "assume input is in base-64 format"
-msgstr ""
+msgstr "forvent inndata i «base-64»-format"
 
 msgid "assume input is in binary format"
-msgstr ""
+msgstr "forvent inndata i binærformat"
 
 msgid "never consult a CRL"
-msgstr ""
+msgstr "aldri spør CRL"
 
 msgid "check validity using OCSP"
-msgstr ""
+msgstr "kontroller gyldighet med OCSP"
 
 msgid "|N|number of certificates to include"
-msgstr ""
+msgstr "|N|antall sertifikater som skal være med"
 
 msgid "|FILE|take policy information from FILE"
-msgstr ""
+msgstr "|FIL|hent regler fra valgt FIL"
 
 msgid "do not check certificate policies"
-msgstr ""
+msgstr "ikke kontroller sertifikatregler"
 
 msgid "fetch missing issuer certificates"
-msgstr ""
+msgstr "hent manglende utstedersertifikat"
 
 msgid "don't use the terminal at all"
-msgstr ""
+msgstr "ikke bruk terminal i det hele tatt"
 
 msgid "|FILE|write a server mode log to FILE"
-msgstr ""
+msgstr "|FIL|lagre en tjenermodus-logg i valgt FIL"
 
-#, fuzzy
 msgid "|FILE|write an audit log to FILE"
-msgstr "leser valg fra «%s»\n"
+msgstr "|FIL|lagre en revisjonslogg i valgt FIL"
 
 msgid "batch mode: never ask"
-msgstr ""
+msgstr "buntmodus: aldri spør"
 
 msgid "assume yes on most questions"
-msgstr ""
+msgstr "svar automatisk ja på de fleste spørsmål"
 
 msgid "assume no on most questions"
-msgstr ""
+msgstr "svar automatisk nei på de fleste spørsmål"
 
-#, fuzzy
 msgid "|FILE|add keyring to the list of keyrings"
-msgstr "hent nøklene fra dette nøkkelknippet"
+msgstr "|FIL|legg til nøkkelknippe i liste over nøkkelknipper"
 
 msgid "|USER-ID|use USER-ID as default secret key"
-msgstr ""
+msgstr "|BRUKER-ID|bruk valgt BRUKER-ID som forvalgt hemmelig nøkkel"
 
 msgid "|SPEC|use this keyserver to lookup keys"
-msgstr ""
+msgstr "|SPEC|bruk valgt nøkkeltjener til å slå opp nøkler"
 
-#, fuzzy
 msgid "|NAME|use cipher algorithm NAME"
-msgstr "ukjent kryptoalgoritme"
+msgstr "|NAVN|bruk valgt krypteringsalgoritme-NAVN"
 
-#, fuzzy
 msgid "|NAME|use message digest algorithm NAME"
-msgstr "%s signatur, digestalgoritme %s\n"
+msgstr "|NAVN|bruk valgt summeringsalgoritme-NAVN for melding"
 
-#, fuzzy
-#| msgid "Usage: gpg [options] [files] (-h for help)"
 msgid "Usage: @GPGSM@ [options] [files] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: @GPGSM@ [valg] [filer] (-h for hjelp)"
 
-#, fuzzy
 msgid ""
 "Syntax: @GPGSM@ [options] [files]\n"
 "Sign, check, encrypt or decrypt using the S/MIME protocol\n"
 "Default operation depends on the input data\n"
 msgstr ""
-"Bruksmåte: gpg [valg] [filer]\n"
-"signere, sjekke, kryptere eller dekryptere\n"
-"standard operasjon avhenger av inputdata\n"
+"Syntaks: gpg [valg] [filer]\n"
+"Signer, kontroller, krypter eller dekrypter.\n"
+"Forvalgt handling avhenger av inndata.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Note: won't be able to encrypt to '%s': %s\n"
-msgstr "kan ikke opprette «%s»: %s\n"
+msgstr "Merk: det er ikke mulig å kryptere til «%s». %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unknown validation model '%s'\n"
-msgstr "ukjent valg «%s»\n"
+msgstr "«%s» er en ukjent kontrollmodell\n"
 
 #, c-format
 msgid "%s:%u: no hostname given\n"
-msgstr ""
+msgstr "%s:%u: vertsnavn mangler\n"
 
 #, c-format
 msgid "%s:%u: password given without user\n"
-msgstr ""
+msgstr "%s:%u: passord skrevet inn uten brukernavn\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s:%u: skipping this line\n"
-msgstr "  s = hopp over denne nøkkelen\n"
+msgstr "%s:%u: hopper over denne linja\n"
 
-#, fuzzy
 msgid "could not parse keyserver\n"
-msgstr "kunne ikke parse nøkkelserverens URL\n"
+msgstr "klarte ikke å tolke nøkkeltjener\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "importing common certificates '%s'\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "importerer sertifikat «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't sign using '%s': %s\n"
-msgstr "kan ikke aksere «%s»: %s\n"
+msgstr "klarte ikke Ã¥ signere med Â«%s»: %s\n"
 
 msgid "invalid command (there is no implicit command)\n"
-msgstr ""
+msgstr "ugyldig kommando (implisitt kommando finnes ikke)\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "total number processed: %lu\n"
-msgstr "Totalt antall behandlet: %lu\n"
+msgstr "totalt antall behandlet: %lu\n"
 
-#, fuzzy
 msgid "error storing certificate\n"
-msgstr "generere et opphevingssertifikat"
+msgstr "feil under lagring av sertifikat\n"
 
 msgid "basic certificate checks failed - not imported\n"
-msgstr ""
+msgstr "enkel sertifikatkontroll mislyktes. Ikke importert\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting stored flags: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av lagrede valg: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error importing certificate: %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under importering av sertifikat: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading input: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av inndata: %s\n"
 
-#, fuzzy
 msgid "failed to get the fingerprint\n"
-msgstr "klarte ikke å lagre fingeravtrykket: %s\n"
+msgstr "klarte ikke å hente fingeravtrykk\n"
 
 #, c-format
 msgid "problem looking for existing certificate: %s\n"
-msgstr ""
+msgstr "klarte ikke å søke etter sertifikat: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error finding writable keyDB: %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under søk etter skrivbar nøkkeldatabase: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error storing certificate: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under lagring av sertifikat: %s\n"
 
 #, c-format
 msgid "problem re-searching certificate: %s\n"
-msgstr ""
+msgstr "det oppstod en feil under nytt søk etter sertifikat: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error storing flags: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lagring av valg: %s\n"
 
 msgid "Error - "
-msgstr ""
+msgstr "Feil - "
 
 msgid "GPG_TTY has not been set - using maybe bogus default\n"
-msgstr ""
+msgstr "GPG_TTY har ingen verdi. Bruker forvalgt verdi som kan være ugyldig\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid formatted fingerprint in '%s', line %d\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "feilformatert fingeravtrykk i «%s», linje %d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid country code in '%s', line %d\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "ugyldig landskode i «%s», linje %d\n"
 
 #, c-format
 msgid ""
@@ -6963,11 +6753,19 @@ msgid ""
 "\n"
 "%s%sAre you really sure that you want to do this?"
 msgstr ""
+"Du er i ferd med å lage en signatur med følgende sertifikat:\n"
+"«%s»\n"
+"Dette fører til en signatur som lovmessig kan tilsvare håndskrevede "
+"signaturer.\n"
+"\n"
+"%s%sEr du sikker på at du vil gjøre dette?"
 
 msgid ""
 "Note, that this software is not officially approved to create or verify such "
 "signatures.\n"
 msgstr ""
+"Merk: dette programmet er ikke offisielt godkjent for å lage eller bekrefte "
+"slike signaturer.\n"
 
 #, c-format
 msgid ""
@@ -6975,607 +6773,584 @@ msgid ""
 "\"%s\"\n"
 "Note, that this certificate will NOT create a qualified signature!"
 msgstr ""
+"Du er i ferd med å lage en signatur med følgende sertifikat:\n"
+"«%s»\n"
+"Merk: dette sertifikatet lager ikke «kvalifiserte» signaturer."
 
 #, c-format
 msgid "hash algorithm %d (%s) for signer %d not supported; using %s\n"
 msgstr ""
+"kontrollsum-algoritme %d (%s) for undertegnet %d støttes ikke. Bruker %s\n"
 
 #, c-format
 msgid "hash algorithm used for signer %d: %s (%s)\n"
-msgstr ""
+msgstr "kontrollsum-algoritme brukt av undertegnet %d: %s (%s)\n"
 
 #, c-format
 msgid "checking for qualified certificate failed: %s\n"
-msgstr ""
+msgstr "søk etter godkjent sertifikat mislyktes: %s\n"
 
-#, fuzzy
 msgid "Signature made "
-msgstr "Signatur opprettet %s\n"
+msgstr "Signatur fullført"
 
 msgid "[date not given]"
-msgstr ""
+msgstr "[dato ikke oppgitt]"
 
-#, fuzzy, c-format
+#, c-format
 msgid " using certificate ID 0x%08lX\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr " ved bruk av sertifikat-ID 0x%08lX\n"
 
 msgid ""
 "invalid signature: message digest attribute does not match computed one\n"
 msgstr ""
+"ugyldig signatur. Kontrollsum-attributt for melding samsvarer ikke med "
+"attributt for utregnet sum\n"
 
-#, fuzzy
 msgid "Good signature from"
-msgstr "God signatur fra «%s»"
+msgstr "Gyldig signatur fra"
 
-#, fuzzy
 msgid "                aka"
-msgstr "                aka «%s»"
+msgstr "                også kjent som"
 
-#, fuzzy
 msgid "This is a qualified signature\n"
-msgstr "Dette vil være en selvsignatur.\n"
+msgstr "Dette er en godkjent signatur\n"
 
 #, c-format
 msgid "can't initialize certificate cache lock: %s\n"
-msgstr ""
+msgstr "klarte ikke å starte låsing av sertifikat-hurtiglager. %s\n"
 
 #, c-format
 msgid "can't acquire read lock on the certificate cache: %s\n"
-msgstr ""
+msgstr "klarte ikke å sperre sertifikat-hurtiglager for lesing. %s\n"
 
 #, c-format
 msgid "can't acquire write lock on the certificate cache: %s\n"
-msgstr ""
+msgstr "klarte ikke å sperre sertifikat-hurtiglager for skriving. %s\n"
 
 #, c-format
 msgid "can't release lock on the certificate cache: %s\n"
-msgstr ""
+msgstr "klarte ikke å låse opp sertifikat-hurtiglager. %s\n"
 
 #, c-format
 msgid "dropping %u certificates from the cache\n"
-msgstr ""
+msgstr "fjerner %u sertifikater fra hurtiglager\n"
 
-#, fuzzy, c-format
-#| msgid "can't create directory `%s': %s\n"
+#, c-format
 msgid "can't access directory '%s': %s\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "fikk ikke tilgang til mappa Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't create `%s': %s\n"
+#, c-format
 msgid "can't parse certificate '%s': %s\n"
-msgstr "kan ikke opprette «%s»: %s\n"
+msgstr "klarte ikke Ã¥ tolke sertifikat Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "certificate '%s' already cached\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "sertifikat «%s» ligger allerede i hurtiglager\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "trusted certificate '%s' loaded\n"
-msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - avvist\n"
+msgstr "lastet inn tillitsmerket sertifikat «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "certificate '%s' loaded\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "lastet inn sertifikat «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "  SHA1 fingerprint = %s\n"
-msgstr "CA-fingeravtrykk: "
+msgstr "  SHA1-fingeravtrykk = %s\n"
 
 msgid "   issuer ="
-msgstr ""
+msgstr "   utsteder ="
 
 msgid "  subject ="
-msgstr ""
+msgstr "  emne ="
 
-#, fuzzy, c-format
+#, c-format
 msgid "error loading certificate '%s': %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under innlasting av sertifikat «%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "permanently loaded certificates: %u\n"
-msgstr "ugyldig sertifikat"
+msgstr "permanent innlastede sertifikater: %u\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "    runtime cached certificates: %u\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "    hurtiglagrede sertifikater: %u\n"
 
-#, fuzzy
 msgid "certificate already cached\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "sertifikat allerede hurtiglagret\n"
 
-#, fuzzy
 msgid "certificate cached\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "sertifikat hurtiglagret\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error caching certificate: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under hurtiglagring av sertifikat: %s\n"
 
-#, fuzzy, c-format
-#| msgid "invalid fingerprint"
+#, c-format
 msgid "invalid SHA1 fingerprint string '%s'\n"
-msgstr "ugyldig fingeravtrykk"
+msgstr "«%s» er et ugyldig SHA1-fingeravtrykk\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error fetching certificate by S/N: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under henting av sertifikat etter S/N: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error fetching certificate by subject: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under henting av sertifikat etter emne: %s\n"
 
-#, fuzzy
 msgid "no issuer found in certificate\n"
-msgstr "generere et opphevingssertifikat"
+msgstr "fant ingen utsteder av sertifikat\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting authorityKeyIdentifier: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av «authorityKeyIdentifier»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't create directory `%s': %s\n"
+#, c-format
 msgid "creating directory '%s'\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "lager mappe «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error creating directory '%s': %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "feil under oppretting av mappa Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "ignoring database dir '%s'\n"
-msgstr "feil i trailerlinje\n"
+msgstr "ignorerer databasemappe «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading directory '%s': %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av mappa Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "removing cache file '%s'\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "fjerner hurtiglager-fil «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "enarmoring failed: %s\n"
+#, c-format
 msgid "not removing file '%s'\n"
-msgstr "enarmoring failed: %s\n"
+msgstr "lar være å fjerne «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error closing cache file: %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under lukking av hurtiglager-fil: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to open cache dir file '%s': %s\n"
-msgstr "Kan ikke åpne «%s»: %s\n"
+msgstr "klarte ikke Ã¥ Ã¥pne hurtiglagermappe-fil Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error creating new cache dir file '%s': %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under oppretting av ny hurtiglagermappe-fil «%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error writing secret keyring `%s': %s\n"
+#, c-format
 msgid "error writing new cache dir file '%s': %s\n"
-msgstr "feil ved skriving av hemmelig nøkkelknippe «%s»: %s\n"
+msgstr "feil under skriving av ny hurtiglagermappe-fil Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error closing new cache dir file '%s': %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under lukking av ny hurtiglagermappe-fil Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "new configuration file `%s' created\n"
+#, c-format
 msgid "new cache dir file '%s' created\n"
-msgstr "ny konfigurasjonsfil «%s» ble opprettet\n"
+msgstr "ny hurtiglagermappe-fil «%s» opprettet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to re-open cache dir file '%s': %s\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "klarte ikke å åpne hurtiglagermappe-fil «%s» på nytt: %s\n"
 
 #, c-format
 msgid "first record of '%s' is not the version\n"
-msgstr ""
+msgstr "første forekomst av «%s» står ikke i versjonspesifikasjon\n"
 
 msgid "old version of cache directory - cleaning up\n"
-msgstr ""
+msgstr "hurtiglager-mappe er av gammel versjon. Rydder opp\n"
 
 msgid "old version of cache directory - giving up\n"
-msgstr ""
+msgstr "hurtiglager-mappe er av gammel versjon. Gir opp\n"
 
 #, c-format
 msgid "extra field detected in crl record of '%s' line %u\n"
-msgstr ""
+msgstr "fant ekstrafelt i crl-oppføring i «%s» på linje %u\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid line detected in '%s' line %u\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "fant ugyldig linje i «%s» på linje %u\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "duplicate entry detected in '%s' line %u\n"
-msgstr "nøkkel %s: ugyldig opphevingssertifikat: %s - avvist\n"
+msgstr "fant duplikat i «%s» på linje %u\n"
 
 #, c-format
 msgid "unsupported record type in '%s' line %u skipped\n"
-msgstr ""
+msgstr "hoppet over ugyldig elementtype i «%s», linje %u\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid issuer hash in '%s' line %u\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "ugyldig utsteder-kontrollsum i «%s», linje %u\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "no issuer DN in '%s' line %u\n"
-msgstr "lesefeil ved «%s»: %s\n"
+msgstr "ingen utsteder-DN i «%s», linje %u\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid timestamp in '%s' line %u\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "ugyldig tidsstempel i «%s» på linje %u\n"
 
-#, fuzzy, c-format
-#| msgid "WARNING: invalid size of random_seed file - not used\n"
+#, c-format
 msgid "WARNING: invalid cache file hash in '%s' line %u\n"
-msgstr "ADVARSEL: ugyldig størrelse på random_seed-fila - ikke brukt\n"
+msgstr "ADVARSEL: ugyldig kontrollsum av hurtiglager-fil i %s», linje %u\n"
 
 msgid "detected errors in cache dir file\n"
-msgstr ""
+msgstr "fant feil i oppsettsfil for hurtiglager-mappe\n"
 
 msgid "please check the reason and manually delete that file\n"
-msgstr ""
+msgstr "kontroller årsaken og slett fila manuelt\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to create temporary cache dir file '%s': %s\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "klarte ikke Ã¥ lage midlertidig hurtiglagermappe-fil Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error closing '%s': %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under lukking av Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error reading `%s': %s\n"
+#, c-format
 msgid "error renaming '%s' to '%s': %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "klarte ikke Ã¥ gi Â«%s» det nye navnet Â«%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't access `%s': %s\n"
+#, c-format
 msgid "can't hash '%s': %s\n"
-msgstr "kan ikke aksere «%s»: %s\n"
+msgstr "klarte ikke Ã¥ summere Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error setting up MD5 hash context: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under oppsett av MD5-summeringskontekst: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error in `%s': %s\n"
+#, c-format
 msgid "error hashing '%s': %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under summering av Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid formatted checksum for '%s'\n"
-msgstr "Feil: ugyldig formattert fingeravtrykk.\n"
+msgstr "feilformatert kontrollsum av «%s»\n"
 
 msgid "too many open cache files; can't open anymore\n"
-msgstr ""
+msgstr "for mange åpne hurtiglager-filer\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "opening cache file '%s'\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "åpner hurtiglager-fil «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error opening cache file '%s': %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under Ã¥pning av hurtiglager-fil Â«%s»: %s\n"
 
 #, c-format
 msgid "error initializing cache file '%s' for reading: %s\n"
-msgstr ""
+msgstr "feil under åpning av hurtiglager-fil «%s» for lesing. %s\n"
 
 msgid "calling unlock_db_file on a closed file\n"
-msgstr ""
+msgstr "utfører «unlock_db_file» på en lukket fil\n"
 
 msgid "calling unlock_db_file on an unlocked file\n"
-msgstr ""
+msgstr "utfører «unlock_db_file» på en fil som ikke er låst\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to create a new cache object: %s\n"
-msgstr "klarte ikke å lagre nøkkelen: %s\n"
+msgstr "klarte ikke å lage nytt huritglager-objekt: %s\n"
 
 #, c-format
 msgid "no CRL available for issuer id %s\n"
-msgstr ""
+msgstr "ingen CRL tilgjengelig for utsteder-ID %s\n"
 
 #, c-format
 msgid "cached CRL for issuer id %s too old; update required\n"
-msgstr ""
+msgstr "hurtiglagret CRL for utsteder-ID %s er for gammel, og må oppdateres\n"
 
 #, c-format
 msgid ""
 "force-crl-refresh active and %d minutes passed for issuer id %s; update "
 "required\n"
 msgstr ""
+"«force-crl-refresh» er slått på og %d minutter er gått for utsteder-ID %s. "
+"Oppdater hurtiglager.\n"
 
 #, c-format
 msgid "force-crl-refresh active for issuer id %s; update required\n"
 msgstr ""
+"«force-crl-refresh» er slått på for utsteder-ID %s. Oppdater hurtiglager.\n"
 
 #, c-format
 msgid "available CRL for issuer ID %s can't be used\n"
-msgstr ""
+msgstr "tilgjengelig CRL for utsteder-ID %s kan ikke brukes\n"
 
 #, c-format
 msgid "cached CRL for issuer id %s tampered; we need to update\n"
 msgstr ""
+"hurtiglagret CRL for utsteder-ID %s er endret. Hurtiglager må oppdateres\n"
 
 msgid "WARNING: invalid cache record length for S/N "
-msgstr ""
+msgstr "ADVARSEL: ugyldig S/N-lengde på oppføring i hurtiglager"
 
-#, fuzzy, c-format
-#| msgid "Error reading backup key from `%s': %s\n"
+#, c-format
 msgid "problem reading cache record for S/N %s: %s\n"
-msgstr "Feil ved lesing av sikkerhetskopiert nøkkel «%s»: %s\n"
+msgstr "feil under lesing av hurtiglager-oppføring for S/N %s: %s\n"
 
 #, c-format
 msgid "S/N %s is not valid; reason=%02X  date=%.15s\n"
-msgstr ""
+msgstr "S/N %s er ugyldig. grunn=%02X  dato=%.15s\n"
 
 #, c-format
 msgid "S/N %s is valid, it is not listed in the CRL\n"
-msgstr ""
+msgstr "S/N %s er gyldig, men står ikke i CRL\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting data from cache file: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av data fra hurtiglager-fil: %s\n"
 
-#, fuzzy, c-format
-#| msgid "invalid hash algorithm `%s'\n"
+#, c-format
 msgid "unknown hash algorithm '%s'\n"
-msgstr "ugyldig hashalgoritme «%s»\n"
+msgstr "«%s» er en ugyldig summeringsalgoritme\n"
 
 #, c-format
 msgid "gcry_md_open for algorithm %d failed: %s\n"
-msgstr ""
+msgstr "«gcry_md_open» for algoritme %d mislyktes. %s\n"
 
 msgid "got an invalid S-expression from libksba\n"
-msgstr ""
+msgstr "fikk ugyldig S-uttrykk fra libksba\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "converting S-expression failed: %s\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "konvertering av S-uttrykk mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "creating S-expression failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "oppretting av S-uttrykk mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "keyserver send failed: %s\n"
+#, c-format
 msgid "ksba_crl_parse failed: %s\n"
-msgstr "sending til nøkkelserver mislyktes: %s\n"
+msgstr "ksba_crl_parse mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting update times of CRL: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av CRL-oppdateringstid: %s\n"
 
 #, c-format
 msgid "update times of this CRL: this=%s next=%s\n"
-msgstr ""
+msgstr "oppdateringstider for gjeldende CRL: denne=%s neste=%s\n"
 
 msgid "nextUpdate not given; assuming a validity period of one day\n"
-msgstr ""
+msgstr "«nextUpdate» ikke oppgitt. Antar én dags gyldighet\n"
 
-#, fuzzy, c-format
-#| msgid "error getting new PIN: %s\n"
+#, c-format
 msgid "error getting CRL item: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av CRL-element: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error inserting item into temporary cache file: %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under innsetting av element i midlertidig hurtiglager-fil: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "no CRL issuer found in CRL: %s\n"
-msgstr "generere et opphevingssertifikat"
+msgstr "fant ingen CRL-utsteder i CRL: %s\n"
 
 msgid "locating CRL issuer certificate by authorityKeyIdentifier\n"
-msgstr ""
+msgstr "finner CRL-utstedersertifikat med «authorityKeyIdentifier»\n"
 
-#, fuzzy, c-format
-#| msgid "Key generation failed: %s\n"
+#, c-format
 msgid "CRL signature verification failed: %s\n"
-msgstr "Nøkkelgenerering mislyktes: %s\n"
+msgstr "CRL-signaturbekreftelse mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error checking validity of CRL issuer certificate: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under kontroll av gyldighet for CRL-utstedersertifikat: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "ksba_crl_new failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "ksba_crl_new mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "ksba_crl_set_reader failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "ksba_crl_set_reader mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "removed stale temporary cache file '%s'\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "fjernet ødelagt midlertidig hurtiglager-fil «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "problem removing stale temporary cache file '%s': %s\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "feil under fjerning av Ã¸delagt midlertidig hurtiglager-fil Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error creating temporary cache file '%s': %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under opprettelse av midlertidig hurtiglager-fil «%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "update secret failed: %s\n"
+#, c-format
 msgid "crl_parse_insert failed: %s\n"
-msgstr "oppdatering av hemmelig mislyktes: %s\n"
+msgstr "crl_parse_insert mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error finishing temporary cache file '%s': %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under ferdigstillelse av midlertidig hurtiglager-fil Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error closing temporary cache file '%s': %s\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "feil under lukking av midlertidig hurtiglager-fil «%s»: %s\n"
 
 #, c-format
 msgid "WARNING: new CRL still too old; it expired on %s - loading anyway\n"
 msgstr ""
+"ADVARSEL: ny CRL er fremdeles for gammel (utgått %s). Laster inn likevel\n"
 
 #, c-format
 msgid "new CRL still too old; it expired on %s\n"
-msgstr ""
+msgstr "ny CRL er fremdeles for gammel (utgått %s)\n"
 
 #, c-format
 msgid "unknown critical CRL extension %s\n"
-msgstr ""
+msgstr "%s er en ukjent kritisk CRL-utvidelse\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading CRL extensions: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av CRL-utvidelser: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "creating cache file '%s'\n"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "lager hurtiglager-fil «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "renaming `%s' to `%s' failed: %s\n"
+#, c-format
 msgid "problem renaming '%s' to '%s': %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "klarte ikke å endre navn på «%s» til «%s»: %s\n"
 
 msgid ""
 "updating the DIR file failed - cache entry will get lost with the next "
 "program start\n"
 msgstr ""
+"oppdatering av DIR-fil mislyktes. Hurtiglager-oppføring går tapt neste gang "
+"programmet starter\n"
 
 #, c-format
 msgid "Begin CRL dump (retrieved via %s)\n"
-msgstr ""
+msgstr "Start CRL-utskrift (hentet via %s)\n"
 
 msgid ""
 " ERROR: The CRL will not be used because it was still too old after an "
 "update!\n"
 msgstr ""
+" FEIL: CRL blir ikke brukt fordi den fremdeles var for gammel etter "
+"oppdatering.\n"
 
 msgid ""
 " ERROR: The CRL will not be used due to an unknown critical extension!\n"
-msgstr ""
+msgstr " FEIL: CRL blir ikke brukt fordi en kritisk utvidelse er ukjent.\n"
 
 msgid " ERROR: The CRL will not be used\n"
-msgstr ""
+msgstr " FEIL: CRL blir ikke brukt\n"
 
 msgid " ERROR: This cached CRL may have been tampered with!\n"
-msgstr ""
+msgstr " FEIL: Huriglagret CRL kan ha blitt endret av uvedkommende.\n"
 
-#, fuzzy
-#| msgid "WARNING: invalid size of random_seed file - not used\n"
 msgid " WARNING: invalid cache record length\n"
-msgstr "ADVARSEL: ugyldig størrelse på random_seed-fila - ikke brukt\n"
+msgstr " ADVARSEL: ugyldig lengde på oppføring i hurtiglager\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "problem reading cache record: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "klarte ikke å lese hurtiglager-oppføring: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error reading keyblock: %s\n"
+#, c-format
 msgid "problem reading cache key: %s\n"
-msgstr "feil ved lesing av nøkkelblokk: %s\n"
+msgstr "klarte ikke å lese hurtiglager-nøkkel: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading cache entry from db: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av hurtiglager-oppføring fra db: %s\n"
 
 msgid "End CRL dump\n"
-msgstr ""
+msgstr "Avslutt CRL-utskrift\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "crl_fetch via DP failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "crl_fetch via DP mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "crl_cache_insert via DP failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "crl_cache_insert via DP mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "crl_cache_insert via issuer failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "crl_cache_insert via utsteder mislyktes: %s\n"
 
 msgid "reader to file mapping table full - waiting\n"
-msgstr ""
+msgstr "tilknytningstabell for overføring fra leser til fil er full. Venter\n"
 
 msgid "using \"http\" instead of \"https\"\n"
-msgstr ""
+msgstr "bruker «http» i stedet for «https»\n"
 
 #, c-format
 msgid "CRL access not possible due to disabled %s\n"
-msgstr ""
+msgstr "Ingen CRL-tilgang fordi %s er slått av\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error initializing reader object: %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under innlasting av leserobjekt: %s\n"
 
 #, c-format
 msgid "URL '%s' redirected to '%s' (%u)\n"
-msgstr ""
+msgstr "Videresendt fra adresse «%s» til «%s» (%u)\n"
 
-#, fuzzy
-#| msgid "too many cipher preferences\n"
 msgid "too many redirections\n"
-msgstr "for mange cipher-preferanser\n"
+msgstr "for mange videresendinger\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error retrieving '%s': %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under henting av Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error retrieving '%s': http status %u\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under henting av «%s»: http-status %u\n"
 
-#, fuzzy
 msgid "CRL access not possible due to Tor mode\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "Ingen CRL-tilgang i Tor-modus\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "certificate search not possible due to disabled %s\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "sertifikatsøk ikke tilgjengelig fordi %s er slått av\n"
 
 msgid "use OCSP instead of CRLs"
-msgstr ""
+msgstr "bruk OCSP i stedet for CRL"
 
 msgid "check whether a dirmngr is running"
-msgstr ""
+msgstr "kontroller om en dirmngr kjører"
 
-#, fuzzy
 msgid "add a certificate to the cache"
-msgstr "preferansen %s er duplisert\n"
+msgstr "legg til sertifikat i hurtiglager"
 
-#, fuzzy
 msgid "validate a certificate"
-msgstr "ugyldig sertifikat"
+msgstr "kontroller sertifikat"
 
-#, fuzzy
 msgid "lookup a certificate"
-msgstr "ugyldig sertifikat"
+msgstr "slå opp sertifikat"
 
-#, fuzzy
 msgid "lookup only locally stored certificates"
-msgstr "ugyldig sertifikat"
+msgstr "bare slå opp lokalt lagrede sertifikater"
 
 msgid "expect an URL for --lookup"
-msgstr ""
+msgstr "forvent nettadresse for «--lookup»"
 
 msgid "load a CRL into the dirmngr"
-msgstr ""
+msgstr "last inn CRL i dirmngr"
 
 msgid "special mode for use by Squid"
-msgstr ""
+msgstr "spesialmodus til bruk med Squid"
 
-#, fuzzy
 msgid "expect certificates in PEM format"
-msgstr "ugyldig sertifikat"
+msgstr "forvent sertifikater i PEM-format"
 
 msgid "force the use of the default OCSP responder"
-msgstr ""
+msgstr "tving bruk av forvalgt OCSP-svartjeneste"
 
-#, fuzzy
-#| msgid "Usage: gpg [options] [files] (-h for help)"
 msgid "Usage: dirmngr-client [options] [certfile|pattern] (-h for help)\n"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: dirmngr-client [valg] [sert-fil|mønster] (-h for hjelp)\n"
 
 msgid ""
 "Syntax: dirmngr-client [options] [certfile|pattern]\n"
@@ -7583,1451 +7358,1319 @@ msgid ""
 "The process returns 0 if the certificate is valid, 1 if it is\n"
 "not valid and other error codes for general failures\n"
 msgstr ""
+"Syntaks: dirmngr-client [valg] [sert-fil|mønster]\n"
+"Kontroller X.509-sertifikat mot CRL eller utfør OCSP-kontroll.\n"
+"Avslutningskode er 0 hvis sertifikatet er gyldig, 1 hvis\n"
+"ugyldig og annet for generelle programfeil\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading certificate from stdin: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under lesing av sertifikat fra stdin: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading certificate from '%s': %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av sertifikat fra Â«%s»: %s\n"
 
 msgid "certificate too large to make any sense\n"
-msgstr ""
+msgstr "sertifikatet er for stort til at det gir mening\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't connect to the dirmngr: %s\n"
-msgstr "kan ikke åpne nøkkelknippet"
+msgstr "klarte ikke å koble til dirmngr: %s\n"
 
-#, fuzzy, c-format
-#| msgid "update failed: %s\n"
+#, c-format
 msgid "lookup failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "oppslag mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "renaming `%s' to `%s' failed: %s\n"
+#, c-format
 msgid "loading CRL '%s' failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "innlasting av CRL Â«%s» mislyktes: %s\n"
 
 msgid "a dirmngr daemon is up and running\n"
-msgstr ""
+msgstr "dirmngr kjører i bakgrunnen\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "validation of certificate failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "kontroll av sertifikat mislyktes: %s\n"
 
-#, fuzzy
 msgid "certificate is valid\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "sertifikatet er gyldig\n"
 
-#, fuzzy
 msgid "certificate has been revoked\n"
-msgstr "Denne nøkkelen er utgått!"
+msgstr "sertifikatet er opphevet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "certificate check failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "sertifikatkontroll mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't stat `%s': %s\n"
+#, c-format
 msgid "got status: '%s'\n"
-msgstr "kan ikke stat() «%s»: %s\n"
+msgstr "fikk status: «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "error writing secret keyring `%s': %s\n"
+#, c-format
 msgid "error writing base64 encoding: %s\n"
-msgstr "feil ved skriving av hemmelig nøkkelknippe «%s»: %s\n"
+msgstr "feil under skriving av base64-koding: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unsupported inquiry '%s'\n"
-msgstr ""
-"\n"
-"Støttede algoritmer:\n"
+msgstr "spørringa «%s» støttes ikke\n"
 
 msgid "absolute file name expected\n"
-msgstr ""
+msgstr "forventet fullstendig filsti\n"
 
 #, c-format
 msgid "looking up '%s'\n"
-msgstr ""
+msgstr "slår opp «%s»\n"
 
 msgid "run as windows service (background)"
-msgstr ""
+msgstr "kjør som windows-tjeneste (i bakgrunnen)"
 
 msgid "list the contents of the CRL cache"
-msgstr ""
+msgstr "vis innhold i CRL-hurtiglager"
 
-#, fuzzy
 msgid "|FILE|load CRL from FILE into cache"
-msgstr "leser valg fra «%s»\n"
+msgstr "|FIL|last inn CRL fra valgt FIL i hurtiglager"
 
 msgid "|URL|fetch a CRL from URL"
-msgstr ""
+msgstr "|ADR|hent CRL fra valgt nettADResse"
 
 msgid "shutdown the dirmngr"
-msgstr ""
+msgstr "slå av dirmngr"
 
 msgid "flush the cache"
-msgstr ""
+msgstr "tøm hurtiglager"
 
 msgid "|FILE|write server mode logs to FILE"
-msgstr ""
+msgstr "|FIL|skriv tjenermodus-logger til valgt FIL"
 
-#, fuzzy
-#| msgid "Quit without saving? (y/N) "
 msgid "run without asking a user"
-msgstr "Avslutte uten å lagre? (j/N) "
+msgstr "kjør uten å spørre bruker"
 
 msgid "force loading of outdated CRLs"
-msgstr ""
+msgstr "tving innlasting av utdatert CRL"
 
 msgid "allow sending OCSP requests"
-msgstr ""
+msgstr "tillat sending av OCSP-forespørsler"
 
 msgid "inhibit the use of HTTP"
-msgstr ""
+msgstr "hindre bruk av HTTP"
 
 msgid "inhibit the use of LDAP"
-msgstr ""
+msgstr "hindre bruk av LDAP"
 
 msgid "ignore HTTP CRL distribution points"
-msgstr ""
+msgstr "ignorer HTTP CRL-distribusjonspunkter"
 
 msgid "ignore LDAP CRL distribution points"
-msgstr ""
+msgstr "ignorer LDAP CRL-distribusjonspunkter"
 
 msgid "ignore certificate contained OCSP service URLs"
-msgstr ""
+msgstr "ignorer OSCP-tjenesteadresser som følger sertifikater"
 
 msgid "|URL|redirect all HTTP requests to URL"
-msgstr ""
+msgstr "|ADR|videresend alle HTTP-forespørsler til valgt nettADResse"
 
 msgid "|HOST|use HOST for LDAP queries"
-msgstr ""
+msgstr "|VERT|bruk valgt VERT til LDAP-oppslag"
 
 msgid "do not use fallback hosts with --ldap-proxy"
-msgstr ""
+msgstr "ikke bruk tilbakefallsverter ved bruk av valget «--ldap-proxy»"
 
-#, fuzzy
 msgid "|FILE|read LDAP server list from FILE"
-msgstr "leser valg fra «%s»\n"
+msgstr "|FIL|les LDAP-tjenerliste fra valgt FIL"
 
 msgid "add new servers discovered in CRL distribution points to serverlist"
 msgstr ""
+"legg til tjenere i tjenerliste som blir oppdaget via CRL-distribusjonspunkter"
 
 msgid "|N|set LDAP timeout to N seconds"
-msgstr ""
+msgstr "|N|endre LDAP-tidsavbrudd til N antall sekunder"
 
-#, fuzzy
 msgid "|URL|use OCSP responder at URL"
-msgstr "kunne ikke parse nøkkelserverens URL\n"
+msgstr "|ADR|bruk OCSP-svartjeneste ved valgt nettADResse"
 
 msgid "|FPR|OCSP response signed by FPR"
-msgstr ""
+msgstr "|FPR|OCSP-svartjeneste signert av FPR"
 
 msgid "|N|do not return more than N items in one query"
-msgstr ""
+msgstr "|N|ikke vis flere enn N antall elementer per spørring"
 
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
-msgstr ""
+msgstr "|FIL|bruk CA-sertifikater i valgt FIL til HKP via TLS"
 
 msgid "route all network traffic via Tor"
-msgstr ""
+msgstr "kjør all nettverkstrafikk gjennom Tor"
 
-#, fuzzy
-#| msgid ""
-#| "@\n"
-#| "(See the man page for a complete listing of all commands and options)\n"
 msgid ""
 "@\n"
 "(See the \"info\" manual for a complete listing of all commands and "
 "options)\n"
 msgstr ""
 "@\n"
-"(Se mansiden for en komplett liste over alle kommandoene og valgene)\n"
+"Se «info»-bruksanvisning for fullstendig liste over alle kommandoer og valg\n"
 
-#, fuzzy
 msgid "Usage: @DIRMNGR@ [options] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: @DIRMNGR@ [valg] (-h for hjelp)"
 
 msgid ""
 "Syntax: @DIRMNGR@ [options] [command [args]]\n"
 "Keyserver, CRL, and OCSP access for @GNUPG@\n"
 msgstr ""
+"Syntaks: @DIRMNGR@ [valg] [kommando [arg]]\n"
+"Tilgang til nøkkeltjener, CRL og OCSP for @GNUPG@\n"
 
 #, c-format
 msgid "valid debug levels are: %s\n"
-msgstr ""
+msgstr "følgende feilsøkingsnivåer er gyldige: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "usage: %s [options] "
-msgstr "bruksmåte: gpg [valg] "
+msgstr "bruk: %s [valg] "
 
-#, fuzzy
-#| msgid "%s not allowed with %s!\n"
 msgid "colons are not allowed in the socket name\n"
-msgstr "%s er ikke tillatt sammen med %s!\n"
+msgstr "kolon tillates ikke i sokkelnavn\n"
 
-#, fuzzy, c-format
-#| msgid "renaming `%s' to `%s' failed: %s\n"
+#, c-format
 msgid "fetching CRL from '%s' failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "henting av CRL fra Â«%s» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "processing CRL from '%s' failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "behandling av CRL fra Â«%s» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s:%u: line too long - skipped\n"
-msgstr "for lang linje"
+msgstr "%s:%u: for lang linje. Hoppet over\n"
 
-#, fuzzy, c-format
-#| msgid "invalid fingerprint"
+#, c-format
 msgid "%s:%u: invalid fingerprint detected\n"
-msgstr "ugyldig fingeravtrykk"
+msgstr "%s:%u: oppdaget ugyldig fingeravtrykk\n"
 
-#, fuzzy, c-format
-#| msgid "read error in `%s': %s\n"
+#, c-format
 msgid "%s:%u: read error: %s\n"
-msgstr "lesefeil ved «%s»: %s\n"
+msgstr "%s:%u: lesefeil: %s\n"
 
 #, c-format
 msgid "%s:%u: garbage at end of line ignored\n"
-msgstr ""
+msgstr "%s:%u: ignorerer ugyldige data ved linjeslutt\n"
 
 msgid "SIGHUP received - re-reading configuration and flushing caches\n"
-msgstr ""
+msgstr "SIGHUP mottatt. Leser inn oppsett på nytt og tømmer hurtiglagre\n"
 
 msgid "SIGUSR2 received - no action defined\n"
-msgstr ""
+msgstr "SIGUSR2 mottatt. Ingen handling definert\n"
 
 msgid "SIGTERM received - shutting down ...\n"
-msgstr ""
+msgstr "SIGTERM mottatt. Slår av …\n"
 
 #, c-format
 msgid "SIGTERM received - still %d active connections\n"
-msgstr ""
+msgstr "SIGTERM mottatt. %d tilkoblinger er fremdeles aktive\n"
 
-#, fuzzy
-#| msgid "not forced"
 msgid "shutdown forced\n"
-msgstr "ikke tvunget"
+msgstr "slår av under tvang\n"
 
 msgid "SIGINT received - immediate shutdown\n"
-msgstr ""
+msgstr "SIGINT mottatt. Slår av umiddelbart\n"
 
 #, c-format
 msgid "signal %d received - no action defined\n"
-msgstr ""
+msgstr "signal %d mottatt. Ingen handling definert\n"
 
 msgid "return all values in a record oriented format"
-msgstr ""
+msgstr "vis alle verdier i oppføringsorientert format"
 
 msgid "|NAME|ignore host part and connect through NAME"
-msgstr ""
+msgstr "|NAVN|ignorer vertsdel og koble til med NAVN"
 
-#, fuzzy
 msgid "|NAME|connect to host NAME"
-msgstr "|NAVN|kryptere for NAVN"
+msgstr "|NAVN|koble til valgt vertsNAVN"
 
 msgid "|N|connect to port N"
-msgstr ""
+msgstr "|N|koble til port N"
 
 msgid "|NAME|use user NAME for authentication"
-msgstr ""
+msgstr "|NAVN|bruk valgt brukerNAVN til autentisering"
 
 msgid "|PASS|use password PASS for authentication"
-msgstr ""
+msgstr "|PASS|bruk valgt PASSord til autentisering "
 
 msgid "take password from $DIRMNGR_LDAP_PASS"
-msgstr ""
+msgstr "hent passord fra $DIRMNGR_LDAP_PASS"
 
 msgid "|STRING|query DN STRING"
-msgstr ""
+msgstr "|STRENG|utfør spørring med valgt DN-STRENG"
 
 msgid "|STRING|use STRING as filter expression"
-msgstr ""
+msgstr "|STRENG|bruk valgt STRENG som filteruttrykk"
 
 msgid "|STRING|return the attribute STRING"
-msgstr ""
+msgstr "|STRENG|vis attributt valgt med STRENG"
 
-#, fuzzy
-#| msgid "Usage: gpg [options] [files] (-h for help)"
 msgid "Usage: dirmngr_ldap [options] [URL] (-h for help)\n"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: dirmngr_ldap [valg] [ADR] (-h for hjelp)\n"
 
 msgid ""
 "Syntax: dirmngr_ldap [options] [URL]\n"
 "Internal LDAP helper for Dirmngr\n"
 "Interface and options may change without notice\n"
 msgstr ""
+"Syntaks: dirmngr_ldap [valg] [ADR]\n"
+"Internt LDAP-hjelpeverktøy for Dirmngr\n"
+"Grensesnitt og valgmuligheter kan endres uten varsel\n"
 
-#, fuzzy, c-format
-#| msgid "invalid import options\n"
+#, c-format
 msgid "invalid port number %d\n"
-msgstr "ugyldige importvalg\n"
+msgstr "portnummer %d er ugyldig\n"
 
 #, c-format
 msgid "scanning result for attribute '%s'\n"
-msgstr ""
+msgstr "ser gjennom treff for attributt «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error writing to stdout: %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under skriving til std.utkanal: %s\n"
 
 #, c-format
 msgid "          available attribute '%s'\n"
-msgstr ""
+msgstr "          tilgjengelig attributt «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "attribute '%s' not found\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "fant ikke attributt «%s»\n"
 
 #, c-format
 msgid "found attribute '%s'\n"
-msgstr ""
+msgstr "fant attributt «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "reading from `%s'\n"
+#, c-format
 msgid "processing url '%s'\n"
-msgstr "leser fra «%s»\n"
+msgstr "behandler adresse Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "          w/o user IDs: %lu\n"
+#, c-format
 msgid "          user '%s'\n"
-msgstr "               uten brukerider: %lu\n"
+msgstr "          bruker «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "                aka \"%s\""
+#, c-format
 msgid "          pass '%s'\n"
-msgstr "                aka «%s»"
+msgstr "          passord «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "          w/o user IDs: %lu\n"
+#, c-format
 msgid "          host '%s'\n"
-msgstr "               uten brukerider: %lu\n"
+msgstr "          vert «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "          not imported: %lu\n"
+#, c-format
 msgid "          port %d\n"
-msgstr "                ikke importert: %lu\n"
+msgstr "          port %d\n"
 
-#, fuzzy, c-format
-#| msgid "                aka \"%s\""
+#, c-format
 msgid "            DN '%s'\n"
-msgstr "                aka «%s»"
+msgstr "            DN «%s»\n"
 
 #, c-format
 msgid "        filter '%s'\n"
-msgstr ""
+msgstr "        filter «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "                aka \"%s\""
+#, c-format
 msgid "          attr '%s'\n"
-msgstr "                aka «%s»"
+msgstr "          attr «%s»\n"
 
 #, c-format
 msgid "no host name in '%s'\n"
-msgstr ""
+msgstr "ingen vertsnavn i «%s»\n"
 
 #, c-format
 msgid "no attribute given for query '%s'\n"
-msgstr ""
+msgstr "ingen attributt oppgitt for spørring «%s»\n"
 
-#, fuzzy
-#| msgid "WARNING: using insecure memory!\n"
 msgid "WARNING: using first attribute only\n"
-msgstr "ADVARSEL: bruker usikkert minne!\n"
+msgstr "ADVARSEL: bruker bare første attributt\n"
 
-#, fuzzy, c-format
-#| msgid "renaming `%s' to `%s' failed: %s\n"
+#, c-format
 msgid "LDAP init to '%s:%d' failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "LDAP-init til Â«%s:%d» mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "renaming `%s' to `%s' failed: %s\n"
+#, c-format
 msgid "binding to '%s:%d' failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "tilknytning til Â«%s:%d» mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "dearmoring failed: %s\n"
+#, c-format
 msgid "searching '%s' failed: %s\n"
-msgstr "dearmoring failed: %s\n"
+msgstr "søk etter «%s» mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "`%s' is not a JPEG file\n"
+#, c-format
 msgid "'%s' is not an LDAP URL\n"
-msgstr "«%s» er ikke et JPEG-fil\n"
+msgstr "«%s» er ikke en LDAP-adresse\n"
 
 #, c-format
 msgid "'%s' is an invalid LDAP URL\n"
-msgstr ""
+msgstr "«%s» er en ugyldig LDAP-adresse\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error allocating memory: %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+msgstr "feil under tildeling av minne. %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error printing log line: %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under utskrift av logglinje: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading log from ldap wrapper %d: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av logg fra ldap-grensesnitt %d: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "npth_select failed: %s - waiting 1s\n"
-msgstr "oppdatering av hemmelig mislyktes: %s\n"
+msgstr "npth_select mislyktes: %s - venter 1s\n"
 
 #, c-format
 msgid "ldap wrapper %d ready"
-msgstr ""
+msgstr "ldap-grensesnitt %d klart"
 
 #, c-format
 msgid "ldap wrapper %d ready: timeout\n"
-msgstr ""
+msgstr "ldap-grensesnitt %d klart: tidsavbrudd\n"
 
 #, c-format
 msgid "ldap wrapper %d ready: exitcode=%d\n"
-msgstr ""
+msgstr "ldap-grensesnitt %d klart: avslutningskode=%d\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "waiting for ldap wrapper %d failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "venting på ldap-grensesnitt %d mislyktes: %s\n"
 
 #, c-format
 msgid "ldap wrapper %d stalled - killing\n"
-msgstr ""
+msgstr "ldap-grensesnitt %d steilet - dreper prosess\n"
 
 #, c-format
 msgid "error spawning ldap wrapper reaper thread: %s\n"
-msgstr ""
+msgstr "feil under oppbygging av «reaper»-tråd for ldap-grensesnitt: %s\n"
 
-#, fuzzy, c-format
-#| msgid "reading public key failed: %s\n"
+#, c-format
 msgid "reading from ldap wrapper %d failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "lesing fra ldap-grensesnitt %d mislyktes: %s\n"
 
 #, c-format
 msgid "invalid char 0x%02x in host name - not added\n"
-msgstr ""
+msgstr "vertsnavn inneholder ugyldig tegn 0x%02x, og ble ikke lagt til\n"
 
 #, c-format
 msgid "adding '%s:%d' to the ldap server list\n"
-msgstr ""
+msgstr "legger til «%s:%d» i ldap-tjenerliste\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "malloc failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "malloc mislyktes: %s\n"
 
 #, c-format
 msgid "start_cert_fetch: invalid pattern '%s'\n"
-msgstr ""
+msgstr "start_cert_fetch: mønsteret «%s» er ugyldig\n"
 
 msgid "ldap_search hit the size limit of the server\n"
-msgstr ""
+msgstr "ldap_search overskred tjenerens størrelsesgrense\n"
 
 msgid "invalid canonical S-expression found\n"
-msgstr ""
+msgstr "fant ugyldig generelt S-uttrykk\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "gcry_md_open failed: %s\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "«gcry_md_open» mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "update secret failed: %s\n"
+#, c-format
 msgid "oops: ksba_cert_hash failed: %s\n"
-msgstr "oppdatering av hemmelig mislyktes: %s\n"
+msgstr "obs: «ksba_cert_hash» mislyktes: %s\n"
 
 msgid "bad URL encoding detected\n"
-msgstr ""
+msgstr "oppdaget ugyldig URL-koding\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading from responder: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing fra svartjeneste: %s\n"
 
-#, fuzzy, c-format
-#| msgid "Error: Private DO too long (limit is %d characters).\n"
+#, c-format
 msgid "response from server too large; limit is %d bytes\n"
-msgstr "Feil: Privat DO for lang (grensa går ved %d tegn).\n"
+msgstr "for store responsdata fra tjener (grense: %d byte)\n"
 
-#, fuzzy
 msgid "OCSP request not possible due to Tor mode\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "OCSP-forespørsel ikke mulig i Tor-modus\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
-msgstr ""
+msgstr "OCSP-forespørsel ikke mulig når HTTP er slått av\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error setting OCSP target: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under endring av OCSP-mål: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error building OCSP request: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under bygging av OCSP-forespørsel: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error connecting to '%s': %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under tilkobling til Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading HTTP response for '%s': %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing av HTTP-svar for Â«%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error accessing '%s': http status %u\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "fikk ikke tilgang til «%s»: http-status %u\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error parsing OCSP response for '%s': %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under tolking av OCSP-svar for Â«%s»: %s\n"
 
 #, c-format
 msgid "OCSP responder at '%s' status: %s\n"
-msgstr ""
+msgstr "Status for OCSP-svartjeneste ved «%s»: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "hashing the OCSP response for '%s' failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "summering av OCSP-svar for Â«%s» mislyktes: %s\n"
 
 msgid "not signed by a default OCSP signer's certificate"
-msgstr ""
+msgstr "ikke signert av sertifikat som tilhører en forvalgt OCSP-fullmektig"
 
 msgid "only SHA-1 is supported for OCSP responses\n"
-msgstr ""
+msgstr "OSCP-svar skal bare bruke SHA-1\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "allocating list item failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "tildeling av listeelement mislyktes: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error getting new PIN: %s\n"
+#, c-format
 msgid "error getting responder ID: %s\n"
-msgstr "feil ved henting av ny PIN: %s\n"
+msgstr "feil under henting av svartjeneste-ID: %s\n"
 
 msgid "no suitable certificate found to verify the OCSP response\n"
-msgstr ""
+msgstr "fant ingen sertifikat som egner seg til å bekrefte OCSP-svar\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "issuer certificate not found: %s\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "fant ikke utstedersertifikat: %s\n"
 
 msgid "caller did not return the target certificate\n"
-msgstr ""
+msgstr "klient sendte ikke målsertifikat\n"
 
-#, fuzzy
 msgid "caller did not return the issuing certificate\n"
-msgstr "generere et opphevingssertifikat"
+msgstr "klient sendte ikke utstedersertifikat\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to allocate OCSP context: %s\n"
-msgstr "klarte ikke å lagre nøkkelen: %s\n"
+msgstr "klarte ikke å tildele OCSP-kontekst: %s\n"
 
-#, fuzzy, c-format
-#| msgid "can't access `%s': %s\n"
+#, c-format
 msgid "can't get authorityInfoAccess: %s\n"
-msgstr "kan ikke aksere «%s»: %s\n"
+msgstr "klarte ikke Ã¥ hente Â«authorityInfoAccess»: %s\n"
 
 msgid "no default OCSP responder defined\n"
-msgstr ""
+msgstr "ingen forvalgt OCSP-svartjeneste\n"
 
-#, fuzzy
-#| msgid "no default secret keyring: %s\n"
 msgid "no default OCSP signer defined\n"
-msgstr "ingen standard hemmelig nøkkelknippe: %s\n"
+msgstr "ingen OCSP-undertegner er definert som standard\n"
 
 #, c-format
 msgid "using default OCSP responder '%s'\n"
-msgstr ""
+msgstr "bruker forvalgt OCSP-svartjeneste «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "using cipher %s\n"
+#, c-format
 msgid "using OCSP responder '%s'\n"
-msgstr "bruker cipher %s\n"
+msgstr "bruker OCSP-svartjeneste «%s»\n"
 
 #, c-format
 msgid "failed to establish a hashing context for OCSP: %s\n"
-msgstr ""
+msgstr "klarte ikke å sette opp kontrollsum-kontekst for OCSP: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error getting OCSP status for target certificate: %s\n"
-msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+msgstr "feil under henting av OCSP-status for målsertifikat: %s\n"
 
 #, c-format
 msgid "certificate status is: %s  (this=%s  next=%s)\n"
-msgstr ""
+msgstr "sertifikatstatus er: %s  (dette=%s  neste=%s)\n"
 
 msgid "good"
-msgstr ""
+msgstr "bra"
 
-#, fuzzy, c-format
+#, c-format
 msgid "certificate has been revoked at: %s due to: %s\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+msgstr "sertifikat opphevet %s med følgende begrunnelse: %s\n"
 
 msgid "OCSP responder returned a status in the future\n"
-msgstr ""
+msgstr "OCSP-svartjeneste sendte status datert i fremtid\n"
 
 msgid "OCSP responder returned a non-current status\n"
-msgstr ""
+msgstr "OCSP-svartjeneste sendte status som ikke er datert i nåtid\n"
 
 msgid "OCSP responder returned an too old status\n"
-msgstr ""
+msgstr "OCSP-svartjeneste sendte for gammel status\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "assuan_inquire(%s) failed: %s\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "«assuan_inquire»(%s) mislyktes: %s\n"
 
 msgid "ldapserver missing"
-msgstr ""
+msgstr "ldapserver mangler"
 
 msgid "serialno missing in cert ID"
-msgstr ""
+msgstr "serienummer mangler i sertifikat-ID"
 
-#, fuzzy, c-format
+#, c-format
 msgid "assuan_inquire failed: %s\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "«assuan_inquire» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "fetch_cert_by_url failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "«fetch_cert_by_url» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error sending data: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under sending av data: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "start_cert_fetch failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "«start_cert_fetch» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "fetch_next_cert failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "«fetch_next_cert» mislyktes: %s\n"
 
 #, c-format
 msgid "max_replies %d exceeded\n"
-msgstr ""
+msgstr "max_replies %d overskredet\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't allocate control structure: %s\n"
-msgstr "kan ikke opprette sikkerhetskopifil «%s»: %s\n"
+msgstr "klarte ikke å tildele kontrollstruktur: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to allocate assuan context: %s\n"
-msgstr "klarte ikke å lagre nøkkelen: %s\n"
+msgstr "klarte ikke å tildele assuan-kontekst: %s\n"
 
-#, fuzzy, c-format
-#| msgid "failed to initialize the TrustDB: %s\n"
+#, c-format
 msgid "failed to initialize the server: %s\n"
-msgstr "klarte ikke å initialisere tillitsdatabasen: %s\n"
+msgstr "klarte ikke å starte opp tjener: %s\n"
 
-#, fuzzy, c-format
-#| msgid "failed to store the creation date: %s\n"
+#, c-format
 msgid "failed to the register commands with Assuan: %s\n"
-msgstr "klarte ikke å lagre opprettelsesdatoen: %s\n"
+msgstr "klarte ikke å registrere kommandoer i Assuan: %s\n"
 
 #, c-format
 msgid "Assuan accept problem: %s\n"
-msgstr ""
+msgstr "Assuan-godkjenningsproblem: %s\n"
 
-#, fuzzy, c-format
-#| msgid "signing failed: %s\n"
+#, c-format
 msgid "Assuan processing failed: %s\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "Assuan-behandling mislyktes: %s\n"
 
 msgid "accepting root CA not marked as a CA"
-msgstr ""
+msgstr "godtar rot-CA som ikke er merket som CA"
 
 msgid "CRL checking too deeply nested\n"
-msgstr ""
+msgstr "for mange nivåer av CRL-kontroll\n"
 
 msgid "not checking CRL for"
-msgstr ""
+msgstr "lar være å kontrollere CRL for"
 
-#, fuzzy
 msgid "checking CRL for"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "kontrollerer CRL for"
 
 msgid "running in compatibility mode - certificate chain not checked!\n"
-msgstr ""
+msgstr "kjører i kompatiblitetsmodus. Sertifikatkjede ikke kontrollert.\n"
 
-#, fuzzy
 msgid "selfsigned certificate has a BAD signature"
-msgstr "bekrefte en signatur"
+msgstr "selvsignert sertifikat har ugyldig signatur"
 
-#, fuzzy, c-format
+#, c-format
 msgid "checking trustworthiness of root certificate failed: %s\n"
-msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+msgstr "troverdighetssjekk av rotsertifikat mislyktes: %s\n"
 
-#, fuzzy
 msgid "certificate chain is good\n"
-msgstr "preferansen %s er duplisert\n"
+msgstr "sertifikatkjede er funnet i orden\n"
 
 msgid "DSA requires the use of a 160 bit hash algorithm\n"
-msgstr "DSA krever bruk av en 160-bit hashalgoritme\n"
+msgstr "DSA krever kontrollsum på 160 bit\n"
 
 msgid "certificate should not have been used for CRL signing\n"
-msgstr ""
+msgstr "sertifikat skulle ikke vært brukt til CRL-signering\n"
 
-#, fuzzy
 msgid "quiet"
-msgstr "avslutt"
+msgstr "stille"
 
 msgid "print data out hex encoded"
-msgstr ""
+msgstr "kod utdata i heksadesimaler"
 
 msgid "decode received data lines"
-msgstr ""
+msgstr "dekod mottatte datalinjer"
 
 msgid "connect to the dirmngr"
-msgstr ""
+msgstr "koble til dirmngr"
 
 msgid "|NAME|connect to Assuan socket NAME"
-msgstr ""
+msgstr "|NAVN|koble til valgt Assuan-sokkelNAVN"
 
 msgid "|ADDR|connect to Assuan server at ADDR"
-msgstr ""
+msgstr "|ADR|koble til Assuan-tjener på valgt nettADResse"
 
 msgid "run the Assuan server given on the command line"
-msgstr ""
+msgstr "kjør valgt Assuan-tjener"
 
 msgid "do not use extended connect mode"
-msgstr ""
+msgstr "ikke bruk utvidet tilkoblingsmodus"
 
-#, fuzzy
 msgid "|FILE|run commands from FILE on startup"
-msgstr "leser valg fra «%s»\n"
+msgstr "|FIL|kjør kommandoer fra valgt FIL ved oppstart"
 
 msgid "run /subst on startup"
-msgstr ""
+msgstr "kjør /subst ved oppstart"
 
-#, fuzzy
 msgid "Usage: @GPG@-connect-agent [options] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: @GPG@-connect-agent [vlag] (-h for hjelp)"
 
 msgid ""
 "Syntax: @GPG@-connect-agent [options]\n"
 "Connect to a running agent and send commands\n"
 msgstr ""
+"Syntaks: @GPG@-connect-agent [valg]\n"
+"Koble til kjørende agent og send kommandoer\n"
 
 #, c-format
 msgid "option \"%s\" requires a program and optional arguments\n"
-msgstr ""
+msgstr "valget «%s» krever et program som argument\n"
 
 #, c-format
 msgid "option \"%s\" ignored due to \"%s\"\n"
-msgstr ""
+msgstr "ignorerer valget «%s» pga. «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "receiving line failed: %s\n"
-msgstr "lesing av offentlig nøkkel mislyktes: %s\n"
+msgstr "linjemottak mislyktes: %s\n"
 
-#, fuzzy
 msgid "line too long - skipped\n"
-msgstr "for lang linje"
+msgstr "hoppet over for lang linje\n"
 
 msgid "line shortened due to embedded Nul character\n"
-msgstr ""
+msgstr "linje forkortet pga. innebygget Nul-tegn\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unknown command '%s'\n"
-msgstr "ukjent valg «%s»\n"
+msgstr "«%s» er en ukjent kommando\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "sending line failed: %s\n"
-msgstr "signering mislyktes: %s\n"
+msgstr "sending av linje mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error sending standard options: %s\n"
-msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
+msgstr "feil under sending av standardvalg: %s\n"
 
 msgid "Options controlling the diagnostic output"
-msgstr ""
+msgstr "Styring av diagnostikk-utdata"
 
 msgid "Options controlling the configuration"
-msgstr ""
+msgstr "Oppsettsvalg"
 
 msgid "Options useful for debugging"
-msgstr ""
+msgstr "Nyttige feilsøkingsvalg"
 
 msgid "Options controlling the security"
-msgstr ""
+msgstr "Sikkerhetsvalg"
 
 msgid "|N|expire SSH keys after N seconds"
-msgstr ""
+msgstr "|N|SSH-nøkler utgår etter N antall sekunder"
 
 msgid "|N|set maximum PIN cache lifetime to N seconds"
 msgstr ""
+"|N|endre maksimal livstid for PIN-koder i hurtiglager til N antall sekunder"
 
 msgid "|N|set maximum SSH key lifetime to N seconds"
-msgstr ""
+msgstr "|N|endre maksimal livstid for SSH-nøkler til N antall sekunder"
 
 msgid "Options enforcing a passphrase policy"
-msgstr ""
+msgstr "Valg som håndhever passordfrase-regler"
 
 msgid "do not allow to bypass the passphrase policy"
-msgstr ""
+msgstr "ikke tillat overstyring av passordfrase-regler"
 
 msgid "|N|set minimal required length for new passphrases to N"
-msgstr ""
+msgstr "|N|endre minimal passordfrase-lengde til N"
 
 msgid "|N|require at least N non-alpha characters for a new passphrase"
-msgstr ""
+msgstr "|N|krev at passordfraser inneholder minst N antall spesialtegn og tall"
 
 msgid "|FILE|check new passphrases against pattern in FILE"
-msgstr ""
+msgstr "|FIL|kontroller nye passordfraser mot mønster i valgt FIL"
 
 msgid "|N|expire the passphrase after N days"
-msgstr ""
+msgstr "|N|regn passord som ugyldig etter N antall dager"
 
-#, fuzzy
 msgid "do not allow the reuse of old passphrases"
-msgstr "feil ved opprettelse av passfrase: %s\n"
+msgstr "ikke tillat gjenbruk av gamle passordfraser"
 
 msgid "|N|set the Pinentry timeout to N seconds"
-msgstr ""
+msgstr "|N|endre tidsavbrudd for PIN-inntasting til N antall sekunder"
 
 msgid "|NAME|use NAME as default secret key"
-msgstr ""
+msgstr "|NAVN|bruk valgt NAVN som forvalgt hemmelig nøkkel"
 
-#, fuzzy
 msgid "|NAME|encrypt to user ID NAME as well"
-msgstr "|NAVN|kryptere for NAVN"
+msgstr "|NAVN|krypter også til valgt bruker-id-NAVN"
 
 msgid "|SPEC|set up email aliases"
-msgstr ""
+msgstr "|SPES|sett opp e-post-alias"
 
 msgid "Configuration for Keyservers"
-msgstr ""
+msgstr "Oppsett for nøkkeltjenere"
 
-#, fuzzy
 msgid "|URL|use keyserver at URL"
-msgstr "kunne ikke parse nøkkelserverens URL\n"
+msgstr "|ADR|bruk nøkkeltjener på valgt nettADResse"
 
 msgid "allow PKA lookups (DNS requests)"
-msgstr ""
+msgstr "tillat PKA-oppslag (DNS-forespørsler)"
 
 msgid "|MECHANISMS|use MECHANISMS to locate keys by mail address"
-msgstr ""
+msgstr "|MEKANISMER|bruk valgte MEKANISME til å finne nøkler med e-postadresse"
 
 msgid "disable all access to the dirmngr"
-msgstr ""
+msgstr "slå av all tilgang til dirmngr"
 
 msgid "|NAME|use encoding NAME for PKCS#12 passphrases"
-msgstr ""
+msgstr "|NAVN|bruk valgt kodeNAVN til PKCS#12-passordfraser"
 
 msgid "do not check CRLs for root certificates"
-msgstr ""
+msgstr "ikke se etter rotsertifikater i CRL"
 
 msgid "Options controlling the format of the output"
-msgstr ""
+msgstr "Valg som styrer utdata-format"
 
 msgid "Options controlling the interactivity and enforcement"
-msgstr ""
+msgstr "Valg som styrer grensesnitt og håndheving av regler"
 
 msgid "Options controlling the use of Tor"
-msgstr ""
+msgstr "Valg som styrer bruk av Tor"
 
 msgid "Configuration for HTTP servers"
-msgstr ""
+msgstr "Oppsett for HTTP-tjenere"
 
 msgid "use system's HTTP proxy setting"
-msgstr ""
+msgstr "bruk systemets innstilling for HTTP-mellomtjener"
 
 msgid "Configuration of LDAP servers to use"
-msgstr ""
+msgstr "Oppsett for bruk av LDAP-tjenere"
 
 msgid "LDAP server list"
-msgstr ""
+msgstr "LDAP-tjenerliste"
 
 msgid "Configuration for OCSP"
-msgstr ""
+msgstr "Oppsett for OCSP"
 
 msgid "GPG for OpenPGP"
-msgstr ""
+msgstr "GPG for OpenPGP"
 
 msgid "GPG Agent"
-msgstr ""
+msgstr "GPG Agent"
 
 msgid "Smartcard Daemon"
-msgstr ""
+msgstr "Smartcard-bakgrunnsprosess"
 
 msgid "GPG for S/MIME"
-msgstr ""
+msgstr "GPG for S/MIME"
 
 msgid "Key Acquirer"
-msgstr ""
+msgstr "Nøkkelhenter"
 
-#, fuzzy
 msgid "PIN and Passphrase Entry"
-msgstr "ugyldig passfrase"
+msgstr "Skriving av PIN og passordfrase"
 
-#, fuzzy
 msgid "Component not suitable for launching"
-msgstr "fant ikke offentlig nøkkel"
+msgstr "Komponent egner seg ikke for oppstart"
 
 #, c-format
 msgid "External verification of component %s failed"
-msgstr ""
+msgstr "Ekstern bekreftelse av komponent %s mislyktes"
 
 msgid "Note that group specifications are ignored\n"
-msgstr ""
+msgstr "Merk at gruppespesifikasjoner blir ignorert\n"
 
 msgid "list all components"
-msgstr ""
+msgstr "vis alle komponenter"
 
 msgid "check all programs"
-msgstr ""
+msgstr "kontroller alle programmer"
 
 msgid "|COMPONENT|list options"
-msgstr ""
+msgstr "|KOMPONENT|vis valg"
 
 msgid "|COMPONENT|change options"
-msgstr ""
+msgstr "|KOMPONENT|endre valg"
 
 msgid "|COMPONENT|check options"
-msgstr ""
+msgstr "|KOMPONENT|kontroller valg"
 
 msgid "apply global default values"
-msgstr ""
+msgstr "bruk globale standardverdier"
 
 msgid "get the configuration directories for @GPGCONF@"
-msgstr ""
+msgstr "hent oppsettsmapper for @GPGCONF@"
 
-#, fuzzy
 msgid "list global configuration file"
-msgstr "ukjent konfigurasjonspunkt «%s»\n"
+msgstr "vis global oppsettsfil"
 
-#, fuzzy
 msgid "check global configuration file"
-msgstr "ukjent konfigurasjonspunkt «%s»\n"
+msgstr "kontroller global oppsettsfil"
 
 msgid "reload all or a given component"
-msgstr ""
+msgstr "last inn én eller alle komponenter på nytt"
 
 msgid "launch a given component"
-msgstr ""
+msgstr "last inn valgt komponent"
 
 msgid "kill a given component"
-msgstr ""
+msgstr "drep valgt komponent"
 
 msgid "use as output file"
-msgstr "bruk som outputfil"
+msgstr "bruk som utdatafil"
 
 msgid "activate changes at runtime, if possible"
-msgstr ""
+msgstr "ta i bruk endringer under kjøring, hvis mulig"
 
-#, fuzzy
 msgid "Usage: @GPGCONF@ [options] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: @GPGCONF@ [valg] (-h for hjelp)"
 
 msgid ""
 "Syntax: @GPGCONF@ [options]\n"
 "Manage configuration options for tools of the @GNUPG@ system\n"
 msgstr ""
+"Syntaks: @GPGCONF@ [valg]\n"
+"Behandle oppsettsvalg for verktøy i @GNUPG@-systemet\n"
 
 msgid "Need one component argument"
-msgstr ""
+msgstr "Komponent-argument mangler"
 
-#, fuzzy
 msgid "Component not found"
-msgstr "fant ikke offentlig nøkkel"
+msgstr "Fant ikke komponent"
 
-#, fuzzy
 msgid "No argument allowed"
-msgstr "Admin-kommandoer er ikke tillatt\n"
+msgstr "Ingen argumenter tillatt"
 
-#, fuzzy
 msgid ""
 "@\n"
 "Commands:\n"
 " "
 msgstr ""
-"@Kommandoer:\n"
+"@\n"
+"Kommandoer:\n"
 " "
 
-#, fuzzy
 msgid "decryption modus"
-msgstr "dekryptering mislyktes: %s\n"
+msgstr "dekrypteringsmodus"
 
-#, fuzzy
 msgid "encryption modus"
-msgstr "kryptere data"
+msgstr "krypteringsmodus"
 
 msgid "tool class (confucius)"
-msgstr ""
+msgstr "verktøyklasse (confucius)"
 
-#, fuzzy
 msgid "program filename"
-msgstr "--store [filnavn]"
+msgstr "programfil-navn"
 
 msgid "secret key file (required)"
-msgstr ""
+msgstr "hemmelig nøkkelfil (påkrevet)"
 
 msgid "input file name (default stdin)"
-msgstr ""
+msgstr "inndata-filnavn (forvalgt: standard innkanal)"
 
-#, fuzzy
 msgid "Usage: symcryptrun [options] (-h for help)"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: symcryptrun [valg] (-h for hjelp)"
 
 msgid ""
 "Syntax: symcryptrun --class CLASS --program PROGRAM --keyfile KEYFILE "
 "[options...] COMMAND [inputfile]\n"
 "Call a simple symmetric encryption tool\n"
 msgstr ""
+"Syntaks: symcryptrun --class KLASSE --program PROGRAM --keyfile NØKKELFIL "
+"[valg …] KOMMANDO [inndatafil]\n"
+"Bruk et enkelt symmetrisk krypteringsverktøy\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s on %s aborted with status %i\n"
-msgstr "%s er ikke tillatt sammen med %s!\n"
+msgstr "%s på %s avbrøt med status %i\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s on %s failed with status %i\n"
-msgstr "%s er ikke tillatt sammen med %s!\n"
+msgstr "%s på %s mislyktes med status %i\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "can't create temporary directory '%s': %s\n"
-msgstr "kan ikke opprette katalogen «%s»: %s\n"
+msgstr "klarte ikke Ã¥ lage midlertidig mappe Â«%s»: %s\n"
 
 #, c-format
 msgid "could not open %s for writing: %s\n"
-msgstr ""
+msgstr "klarte ikke å åpne %s for skriving: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error writing to %s: %s\n"
-msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+msgstr "feil under skriving til %s: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error reading from %s: %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
+msgstr "feil under lesing fra %s: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "error closing %s: %s\n"
-msgstr "feil med «%s»: %s\n"
+msgstr "feil under lukking av %s: %s\n"
 
-#, fuzzy
 msgid "no --program option provided\n"
-msgstr "fjernutføring av programmer er ikke støttet\n"
+msgstr "valget «--program» er ikke brukt\n"
 
 msgid "only --decrypt and --encrypt are supported\n"
-msgstr ""
+msgstr "programmet støtter bare «--decrypt» og «--encrypt»\n"
 
 msgid "no --keyfile option provided\n"
-msgstr ""
+msgstr "valget «--keyfile» mangler\n"
 
 msgid "cannot allocate args vector\n"
-msgstr ""
+msgstr "klarte ikke å tildele argumentvektor\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not create pipe: %s\n"
-msgstr "kan ikke opprette «%s»: %s\n"
+msgstr "klarte ikke å lage datarør: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not create pty: %s\n"
-msgstr "kan ikke opprette «%s»: %s\n"
+msgstr "klarte ikke å lage pty: %s\n"
 
 #, c-format
 msgid "could not fork: %s\n"
-msgstr ""
+msgstr "klarte ikke å lage underprosess: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "execv failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "«execv» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "select failed: %s\n"
-msgstr "sleting av nøkkelblokk mislyktes: %s\n"
+msgstr "«select» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "read failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "«read» mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "pty read failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "«pty»-lesing mislyktes: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "waitpid failed: %s\n"
-msgstr "oppdatering mislyktes: %s\n"
+msgstr "«waitpid» mislyktes: %s\n"
 
 #, c-format
 msgid "child aborted with status %i\n"
-msgstr ""
+msgstr "underprosess ble avbrutt med status %i\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "cannot allocate infile string: %s\n"
-msgstr "kan ikke opprette sikkerhetskopifil «%s»: %s\n"
+msgstr "klarte ikke å tildele inndatafil-streng: %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "cannot allocate outfile string: %s\n"
-msgstr "kan ikke opprette sikkerhetskopifil «%s»: %s\n"
+msgstr "klarte ikke å tildele utdatafil-streng: %s\n"
 
 #, c-format
 msgid "either %s or %s must be given\n"
-msgstr ""
+msgstr "du må velge enten %s eller %s\n"
 
 msgid "no class provided\n"
-msgstr ""
+msgstr "ingen klasse valgt\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "class %s is not supported\n"
-msgstr "ikke støttet"
+msgstr "klassen %s støttes ikke\n"
 
-#, fuzzy
 msgid "Usage: gpg-check-pattern [options] patternfile (-h for help)\n"
-msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+msgstr "Bruk: gpg-check-pattern [valg] mønsterfil (-h for hjelp)\n"
 
 msgid ""
 "Syntax: gpg-check-pattern [options] patternfile\n"
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
+"Syntaks: gpg-check-pattern [valg] mønsterfil\n"
+"Kontroller passordfrase oppgitt på standard innkanal mot valgt mønsterfil\n"
 
 #~ msgid "you found a bug ... (%s:%d)\n"
-#~ msgstr "du fant en feil ... (%s:%d)\n"
+#~ msgstr "du fant en feil  (%s:%d)\n"
 
-#, fuzzy
-#~| msgid "%d user IDs without valid self-signatures detected\n"
 #~ msgid "%d user ID without valid self-signature detected\n"
 #~ msgid_plural "%d user IDs without valid self-signatures detected\n"
-#~ msgstr[0] "%d brukerider uten gyldige selvsignaturer ble oppdaget\n"
-#~ msgstr[1] "%d brukerider uten gyldige selvsignaturer ble oppdaget\n"
+#~ msgstr[0] "oppdaget %d bruker-ID uten gyldig selvsignatur\n"
+#~ msgstr[1] "oppdaget %d bruker-id-er uten gyldige selvsignaturer\n"
 
 #~ msgid "moving a key signature to the correct place\n"
-#~ msgstr "flytter en nøkkelsignatur til den rette plassen\n"
+#~ msgstr "flytter en nøkkelsignatur til den rette plassen\n"
 
-#~ msgid "%d signatures not checked due to missing keys\n"
-#~ msgstr "%d signaturer ble ikke sjekket på grunn av manglende nøkler\n"
-
-#~ msgid "%d signatures not checked due to errors\n"
-#~ msgstr "%d signaturer ble ikke sjekket på grunn av feil\n"
+#~ msgid "%d day"
+#~ msgid_plural "%d days"
+#~ msgstr[0] "%d dag"
+#~ msgstr[1] "%d dager"
 
-#~ msgid "1 user ID without valid self-signature detected\n"
-#~ msgstr "1 brukerid uten gyldig selvsignatur ble oppdaget\n"
-
-#~ msgid "Deleted %d signatures.\n"
-#~ msgstr "Slettet %d signaturer.\n"
+#~ msgid "TOFU: few signatures %d message %s"
+#~ msgid_plural "TOFU: few signatures %d messages %s"
+#~ msgstr[0] "TOFU: få signaturer %d melding %s"
+#~ msgstr[1] "TOFU: få signaturer %d meldinger %s"
 
-#, fuzzy
-#~ msgid "User ID \"%s\": %d signatures removed\n"
-#~ msgstr "nøkkel: %s: «%s» %d nye signaturer\n"
+#~ msgid "can't gen prime with pbits=%u qbits=%u\n"
+#~ msgstr "du kan ikke lage primtall med pbits=%u qbits=%u\n"
 
-#~ msgid ""
-#~ "You need a Passphrase to protect your secret key.\n"
-#~ "\n"
-#~ msgstr ""
-#~ "Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-#~ "\n"
+#~ msgid "can't generate a prime with less than %d bits\n"
+#~ msgstr "du kan ikke lage primtall med færre enn %d bit\n"
 
-#, fuzzy
-#~ msgid ""
-#~ "Please enter a passphrase to protect the off-card backup of the new "
-#~ "encryption key."
-#~ msgstr ""
-#~ "Du trenger en passfrase for å beskytte din hemmelige nøkkel.\n"
-#~ "\n"
+#~ msgid "no entropy gathering module detected\n"
+#~ msgstr "fant ingen innsamlingsmodul for vilkårlighetsdata\n"
 
-#~ msgid "passphrase not correctly repeated; try again"
-#~ msgstr "passfrasen ble ikke gjentatt korrekt; prøv igjen"
+#~ msgid "can't lock `%s': %s\n"
+#~ msgstr "klarte ikke å låse «%s». %s\n"
 
-#~ msgid "%s.\n"
-#~ msgstr "%s.\n"
+#~ msgid "`%s' is not a regular file - ignored\n"
+#~ msgstr "«%s» er ikke en vanlig fil, og blir ignorert\n"
 
-#~ msgid ""
-#~ "You don't want a passphrase - this is probably a *bad* idea!\n"
-#~ "I will do it anyway.  You can change your passphrase at any time,\n"
-#~ "using this program with the option \"--edit-key\".\n"
-#~ "\n"
-#~ msgstr ""
-#~ "Du vil ikke ha en passfrase - dette er sannsynligvis en *dum* idé!\n"
-#~ "Jeg fortsetter likevel. Du kan endre passfrasen din når som helst ved\n"
-#~ "hjelp av dette programmet og valget «--edit-key».\n"
-#~ "\n"
+#~ msgid "note: random_seed file is empty\n"
+#~ msgstr "merk: random_seed-fila er tom\n"
 
-#~ msgid "storing key onto card failed: %s\n"
-#~ msgstr "lagring av nøkkel på kort mislyktes: %s\n"
+#~ msgid "can't read `%s': %s\n"
+#~ msgstr "klarte ikke å lese «%s». %s\n"
 
-#, fuzzy
-#~| msgid "1 bad signature\n"
-#~ msgid "1 good signature\n"
-#~ msgstr "1 ubrukelig signatur\n"
+#~ msgid "note: random_seed file not updated\n"
+#~ msgstr "merk: random_seed-fila ble ikke oppdatert\n"
 
-#, fuzzy
-#~| msgid "renaming `%s' to `%s' failed: %s\n"
-#~ msgid "renaming '%s' to '%s' failed: %s\n"
-#~ msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
+#~ msgid "can't write `%s': %s\n"
+#~ msgstr "klarte ikke å skrive «%s». %s\n"
 
-#~ msgid "%lu keys cached (%lu signatures)\n"
-#~ msgstr "%lu nøkler cachet (%lu signaturer)\n"
+#~ msgid "can't close `%s': %s\n"
+#~ msgstr "klarte ikke å lukke «%s». %s\n"
 
-#~ msgid "refreshing 1 key from %s\n"
-#~ msgstr "oppfrisker 1 nøkkel fra %s\n"
+#~ msgid "WARNING: using insecure random number generator!!\n"
+#~ msgstr "ADVARSEL: bruker usikker vikårlighetsgenerator.\n"
 
-# Er dette flertallsformen av denne og den forrige strengen?
 #~ msgid ""
-#~ "key %s was created %lu seconds in the future (time warp or clock "
-#~ "problem)\n"
+#~ "The random number generator is only a kludge to let\n"
+#~ "it run - it is in no way a strong RNG!\n"
+#~ "\n"
+#~ "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n"
+#~ "\n"
 #~ msgstr ""
-#~ "nøkkel %s ble opprettet %lu sekunder i fremtiden (time warp eller "
-#~ "klokkeproblem)\n"
-
-#, fuzzy
-#~| msgid "failed to store the key: %s\n"
-#~ msgid "Failed to open the keyring DB.\n"
-#~ msgstr "klarte ikke å lagre nøkkelen: %s\n"
-
-#, fuzzy
-#~ msgid "Failed to parse '%s'.\n"
-#~ msgstr "Kan ikke åpne «%s»: %s\n"
-
-#, fuzzy
-#~| msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgid "error looking up secret key \"%s\": %s\n"
-#~ msgstr "feil ved lesing av hemmelig nøkkelblokk «%s»: %s\n"
-
-#~ msgid "Please select at most one subkey.\n"
-#~ msgstr "Vennligst velg minst en undernøkkel.\n"
-
-#~ msgid "toggle between the secret and public key listings"
-#~ msgstr "veksle mellom hemmelig og offentlig nøkkellisting"
-
-#~ msgid "Please use the command \"toggle\" first.\n"
-#~ msgstr "Vennligst bruk kommandoen «toggle» først.\n"
+#~ "Denne vilkårlighetsgeneratoren er bare en omvei for å få programmet\n"
+#~ "til å kjøre. Den er på ingen måte en sterk RNG.\n"
+#~ "\n"
+#~ "IKKE BRUK DATA SOM ER GENERERT AV DETTE PROGRAMMET.\n"
+#~ "\n"
 
-#, fuzzy
-#~ msgid "Passphrase"
-#~ msgstr "ugyldig passfrase"
+#~ msgid ""
+#~ "Please wait, entropy is being gathered. Do some work if it would\n"
+#~ "keep you from getting bored, because it will improve the quality\n"
+#~ "of the entropy.\n"
+#~ msgstr ""
+#~ "Vent mens programmet samler inn vilkårlighetsdata. Gjør gjerne noe annet "
+#~ "på maskinen\n"
+#~ "imens da aktivitet kan forbedre kvaliteten på vilkårlighetsdataene.\n"
 
-#, fuzzy
-#~| msgid "WARNING: keyserver option `%s' is not used on this platform\n"
-#~ msgid "WARNING: keyserver option '%s' is not used on this platform\n"
+#~ msgid ""
+#~ "\n"
+#~ "Not enough random bytes available.  Please do some other work to give\n"
+#~ "the OS a chance to collect more entropy! (Need %d more bytes)\n"
 #~ msgstr ""
-#~ "ADVARSEL: nøkkelserver-valget «%s» er ikke i bruk på denne plattformen\n"
+#~ "\n"
+#~ "Ikke nok vilkårlighetsdata tilgjengelig. Gjør noe annet på datamaskinen\n"
+#~ "for å gi operativsystemet en sjanse til å samle mer vilkårlighet.\n"
+#~ "(%d byte mangler)\n"
 
-#, fuzzy
-#~ msgid "use a standard location for the socket"
-#~ msgstr "sette en notasjon for de valgte brukeridene"
+#~ msgid "unknown key protection algorithm\n"
+#~ msgstr "ukjent nøkkelbeskyttelsesalgoritme\n"
 
-#, fuzzy
-#~ msgid "Usage: gpg-agent [options] (-h for help)"
-#~ msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
+#~ msgid "secret parts of key are not available\n"
+#~ msgstr "hemmelige deler av nøkkelen er ikke tilgjengelig.\n"
 
-#, fuzzy
-#~ msgid "error creating socket: %s\n"
-#~ msgstr "feil ved lesing av nøkkelblokk: %s\n"
+#~ msgid "secret key already stored on a card\n"
+#~ msgstr "hemmelig nøkkel er allerede lagret på et kort\n"
 
-#, fuzzy
-#~ msgid "host not found"
-#~ msgstr "[Brukerid ikke funnet]"
+#~ msgid "card reader not available\n"
+#~ msgstr "kortleser er ikke tilgjengelig\n"
 
-#~ msgid "unknown key protection algorithm\n"
-#~ msgstr "ukjent nøkkelbeskyttelsesalgoritme\n"
+#~ msgid "Please insert the card and hit return or enter 'c' to cancel: "
+#~ msgstr "Sett inn kortet og trykk enter, eller trykk «c» for å avbryte: "
 
-#~ msgid "secret parts of key are not available\n"
-#~ msgstr "hemmelige deler av nøkkelen er ikke tilgjengelig.\n"
+#~ msgid "Hit return when ready or enter 'c' to cancel: "
+#~ msgstr "Trykk enter når du er klar, eller trykk «c» for å avbryte: "
 
-#~ msgid "secret key already stored on a card\n"
-#~ msgstr "hemmelig nøkkel er allerede lagret på et kort\n"
+#~ msgid "Enter New Admin PIN: "
+#~ msgstr "Tast ny Admin-PIN: "
 
-#, fuzzy
-#~ msgid "error writing key to card: %s\n"
-#~ msgstr "feil ved skriving av nøkkelknippet «%s»: %s\n"
+#~ msgid "Enter New PIN: "
+#~ msgstr "Tast ny PIN: "
+
+#~ msgid "Enter Admin PIN: "
+#~ msgstr "Tast Admin-PIN: "
 
 #~ msgid ""
 #~ "you can only encrypt to RSA keys of 2048 bits or less in --pgp2 mode\n"
 #~ msgstr ""
-#~ "du kan bare kryptere med RSA-nøkler med lengder på 2048 bits eller mindre "
-#~ "i --pgp2-modus\n"
+#~ "du kan bare kryptere med RSA-nøkler som er 2048 bit eller kortere i «--"
+#~ "pgp2»-modus\n"
 
 #~ msgid ""
 #~ "unable to use the IDEA cipher for all of the keys you are encrypting to.\n"
 #~ msgstr ""
-#~ "klarte ikke å bruke IDEA-algoritmen for alle nøklene du krypterer til.\n"
+#~ "klarte ikke å bruke IDEA-algoritmen for alle nøklene du krypterer til.\n"
 
 #~ msgid "key %s: not protected - skipped\n"
-#~ msgstr "nøkkel %s: ikke beskyttet - hoppet over\n"
+#~ msgstr "nøkkel %s: ikke beskyttet - hoppet over\n"
+
+#~ msgid "about to export an unprotected subkey\n"
+#~ msgstr "du er i ferd med å eksportere en undernøkkel uten beskyttelse\n"
 
 #~ msgid "failed to unprotect the subkey: %s\n"
-#~ msgstr "klarte ikke å fjerne beskyttelsen på undernøkkelen: %s\n"
+#~ msgstr "klarte ikke å fjerne beskyttelsen på undernøkkelen: %s\n"
 
 #~ msgid "WARNING: secret key %s does not have a simple SK checksum\n"
-#~ msgstr "ADVARSEL: hemmelig nøkkel %s har ikke en enkel SK-sjekksum\n"
+#~ msgstr "ADVARSEL: hemmelig nøkkel %s har ikke en enkel SK-sjekksum\n"
 
-#~ msgid "too many entries in pk cache - disabled\n"
-#~ msgstr "for mange innslag i pk-cachen - utkoblet\n"
-
-#~ msgid "no secret subkey for public subkey %s - ignoring\n"
-#~ msgstr ""
-#~ "ingen hemmelig undernøkkel for offentlig undernøkkel %s - ignorerer\n"
-
-#~ msgid "key %s: secret key without public key - skipped\n"
-#~ msgstr "nøkkel %s: hemmelig nøkkel uten offentlig nøkkel - hoppet over\n"
+#~ msgid "generate PGP 2.x compatible messages"
+#~ msgstr "lag meldinger som fungerer med PGP 2.x"
 
-#~ msgid "usage: gpg [options] "
-#~ msgstr "bruksmåte: gpg [valg] "
+#~ msgid "NOTE: %s is not available in this version\n"
+#~ msgstr "MERK: %s er ikke tilgjengelig i denne versjonen\n"
 
 #~ msgid ""
 #~ "you can only make detached or clear signatures while in --pgp2 mode\n"
 #~ msgstr "du kan bare lage adskilte eller klare signaturer i --pgp2-modus\n"
 
 #~ msgid "you can't sign and encrypt at the same time while in --pgp2 mode\n"
-#~ msgstr "du kan ikke signere og kryptere samtidig i --pgp2-modus\n"
+#~ msgstr "du kan ikke signere og kryptere samtidig i «--pgp2»-modus\n"
 
 #~ msgid ""
 #~ "you must use files (and not a pipe) when working with --pgp2 enabled.\n"
-#~ msgstr "du må bruke filer (og ikke en pipe) når --pgp2 er påslått\n"
+#~ msgstr "du må bruke filer (og ikke en pipe) når --pgp2 er påslått\n"
 
 #~ msgid "encrypting a message in --pgp2 mode requires the IDEA cipher\n"
 #~ msgstr "kryptering en melding i --pgp2-modus krever IDEA-algoritmen\n"
 
-#~ msgid "key %s: already in secret keyring\n"
-#~ msgstr "nøkkel %s: finnes allerede i hemmelig nøkkelknippe\n"
+#~ msgid "-k[v][v][v][c] [user-id] [keyring]"
+#~ msgstr "-k[v][v][v][c] [bruker-ID] [nøkkelknippe]"
 
-#~ msgid "key %s: secret key not found: %s\n"
-#~ msgstr "nøkkel %s: hemmelig nøkkel ikke funnet: %s\n"
+#~ msgid "too many entries in pk cache - disabled\n"
+#~ msgstr "for mange elementer i pk-hurtiglager. Slått av\n"
 
-#~ msgid ""
-#~ "You may not make an OpenPGP signature on a PGP 2.x key while in --pgp2 "
-#~ "mode.\n"
-#~ msgstr ""
-#~ "Du kan ikke lage en OpenPGP-signatur på en PGP-2.x-nøkkel i --pgp2-"
-#~ "modus.\n"
+#~ msgid "key %s: secret key without public key - skipped\n"
+#~ msgstr "nøkkel %s: hemmelig nøkkel uten offentlig nøkkel - hoppet over\n"
 
-#~ msgid "This would make the key unusable in PGP 2.x.\n"
-#~ msgstr "Dette ville gjøre nøkkelen ubrukelig i PGP 2.x.\n"
+#~ msgid "no secret subkey for public subkey %s - ignoring\n"
+#~ msgstr ""
+#~ "ingen hemmelig undernøkkel for offentlig undernøkkel %s - ignorerer\n"
 
-#~ msgid "This key is not protected.\n"
-#~ msgstr "Denne nøkkelen er ikke beskyttet.\n"
+#~ msgid ""
+#~ "It's up to you to assign a value here; this value will never be exported\n"
+#~ "to any 3rd party.  We need it to implement the web-of-trust; it has "
+#~ "nothing\n"
+#~ "to do with the (implicitly created) web-of-certificates."
+#~ msgstr ""
+#~ "Det er opptil deg å tildele dette en verdi. Verdien blir aldri sendt\n"
+#~ "til en tredjepart. Den brukes bare til å implementere et "
+#~ "troverdighetsnett, og har\n"
+#~ "ingenting med (det implisitte) sertifikatnettet å gjøre."
 
-#~ msgid "Key is protected.\n"
-#~ msgstr "Nøkkelen er beskyttet.\n"
+#~ msgid ""
+#~ "To build the Web-of-Trust, GnuPG needs to know which keys are\n"
+#~ "ultimately trusted - those are usually the keys for which you have\n"
+#~ "access to the secret key.  Answer \"yes\" to set this key to\n"
+#~ "ultimately trusted\n"
+#~ msgstr ""
+#~ "GnuPG må vite hvilke nøkler du stoler fullstendig på\n"
+#~ "for å kunne bygge troverdighetsnettet. Nøkler du har tilgang til\n"
+#~ "den hemmelige nøkkelen for inngår vanligvis her. Svar «ja»\n"
+#~ "for å merke denne nøkkelen som absolutt troverdig.\n"
 
-#~ msgid "Can't edit this key: %s\n"
-#~ msgstr "Kan ikke redigere denne nøkkelen: %s\n"
+#~ msgid "If you want to use this untrusted key anyway, answer \"yes\"."
+#~ msgstr "Svar «ja» hvis du vil bruke denne usikre nøkkelen likevel."
 
 #~ msgid ""
-#~ "Enter the new passphrase for this secret key.\n"
-#~ "\n"
-#~ msgstr "Tast inn den nye passfrasen for denne hemmelige nøkklen.\n"
+#~ "Enter the user ID of the addressee to whom you want to send the message."
+#~ msgstr "Skriv inn bruker-ID for mottakeren du vil sende meldinga til."
 
 #~ msgid ""
-#~ "You don't want a passphrase - this is probably a *bad* idea!\n"
+#~ "Select the algorithm to use.\n"
+#~ "\n"
+#~ "DSA (aka DSS) is the Digital Signature Algorithm and can only be used\n"
+#~ "for signatures.\n"
+#~ "\n"
+#~ "Elgamal is an encrypt-only algorithm.\n"
 #~ "\n"
+#~ "RSA may be used for signatures or encryption.\n"
+#~ "\n"
+#~ "The first (primary) key must always be a key which is capable of signing."
 #~ msgstr ""
-#~ "Du ønsker ikke en passfrase - dette er sannsynligvis en *dum* idé!\n"
-
-#~ msgid "Do you really want to do this? (y/N) "
-#~ msgstr "Vil du virkelig gjøre dette? (j/N) "
-
-#~ msgid "writing secret key stub to `%s'\n"
-#~ msgstr "skriver foreløpig hemmelig nøkkel til «%s»\n"
-
-#~ msgid "writing secret key to `%s'\n"
-#~ msgstr "skriver hemmelig nøkkel til «%s»\n"
-
-#~ msgid "no writable secret keyring found: %s\n"
-#~ msgstr "ingen skrivbart hemmelig nøkkelknippe ble funnet: %s\n"
-
-#~ msgid "WARNING: 2 files with confidential information exists.\n"
-#~ msgstr "ADVARSEL: 2 filer med konfidensiell informasjon finnes.\n"
-
-#~ msgid "searching for names from %s server %s\n"
-#~ msgstr "søke etter navn fra %s server %s\n"
-
-#~ msgid "searching for names from %s\n"
-#~ msgstr "søker etter navn fra %s\n"
-
-#~ msgid "searching for \"%s\" from %s server %s\n"
-#~ msgstr "søke etter «%s» fra %s server %s\n"
-
-#~ msgid "searching for \"%s\" from %s\n"
-#~ msgstr "søker etter «%s» fra %s\n"
-
-#~ msgid "keyserver did not send VERSION\n"
-#~ msgstr "nøkkelserver sendte ikke VERSION\n"
-
-#~ msgid "keyserver timed out\n"
-#~ msgstr "nøkkelserver svarte ikke tidsnok\n"
-
-#~ msgid "keyserver internal error\n"
-#~ msgstr "intern feil ved nøkkelserver\n"
-
-#~ msgid "keyserver communications error: %s\n"
-#~ msgstr "kommunikasjonsfeil med nøkkelserver: %s\n"
-
-#~ msgid "WARNING: unable to parse URI %s\n"
-#~ msgstr "ADVARSEL: klarte ikke å parse URI %s\n"
-
-#~ msgid "Invalid passphrase; please try again"
-#~ msgstr "Ugyldig passfrase; vennligst prøv igjen"
-
-#, fuzzy
-#~ msgid "Usage: scdaemon [options] (-h for help)"
-#~ msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
-
-#, fuzzy
-#~ msgid "Usage: gpgsm [options] [files] (-h for help)"
-#~ msgstr "Bruksmåte: gpg [valg] [filer] (-h for hjelp)"
-
-#, fuzzy
-#~ msgid "usage: gpgconf [options] "
-#~ msgstr "bruksmåte: gpg [valg] "
-
-#, fuzzy
-#~ msgid "failed to allocated keyDB handle\n"
-#~ msgstr "klarte ikke å lagre nøkkelen: %s\n"
-
-#~ msgid "Command> "
-#~ msgstr "Kommando> "
-
-#~ msgid "Please report bugs to <gnupg-bugs@gnu.org>.\n"
-#~ msgstr "Vennligst rapporter feil til <gnupg-bugs@gnu.org>.\n"
-
-#, fuzzy
-#~ msgid "Please report bugs to "
-#~ msgstr "Vennligst rapporter feil til <gnupg-bugs@gnu.org>.\n"
-
-#~ msgid "DSA keypair will have %u bits.\n"
-#~ msgstr "DSA-nøkkelpar vil ha %u bits.\n"
-
-#~ msgid "Repeat passphrase\n"
-#~ msgstr "Gjenta passfrase\n"
-
-#~ msgid "|A|Admin PIN"
-#~ msgstr "|A|Admin PIN"
+#~ "Velg algoritme.\n"
+#~ "\n"
+#~ "DSA (evt. DSS) - digital signaturalgoritme - kan bare brukes\n"
+#~ "til signering.\n"
+#~ "\n"
+#~ "Elgamal kan bare brukes til kryptering.\n"
+#~ "\n"
+#~ "RSA kan brukes til både signering og kryptering.\n"
+#~ "\n"
+#~ "Første nøkkel (primærnøkkel) må alltid være en nøkkel som\n"
+#~ "kan brukes til signering."
 
-#, fuzzy
-#~ msgid "read options from file"
-#~ msgstr "leser valg fra «%s»\n"
+#~ msgid ""
+#~ "In general it is not a good idea to use the same key for signing and\n"
+#~ "encryption.  This algorithm should only be used in certain domains.\n"
+#~ "Please consult your security expert first."
+#~ msgstr ""
+#~ "Du bør generelt ikke signere og kryptere med samme nøkkel.\n"
+#~ "Denne algoritmen bør bare brukes til bestemte formål.\n"
+#~ "Hør med din lokale sikkerhetsekspert hvis du er i tvil."
 
-#~ msgid "generate PGP 2.x compatible messages"
-#~ msgstr "generere PGP 2.x-kompatible meldinger"
+#~ msgid "Enter the size of the key"
+#~ msgstr "Skriv inn nøkkelstørrelse"
 
-#, fuzzy
-#~ msgid "|[FILE]|make a signature"
-#~ msgstr "|[fil]|lage en signatur"
+#~ msgid "Answer \"yes\" or \"no\""
+#~ msgstr "Svar «ja» eller «nei»"
 
-#, fuzzy
-#~ msgid "|[FILE]|make a clear text signature"
-#~ msgstr "|[fil]|lage en klartekstsignatur"
+#~ msgid ""
+#~ "Enter the required value as shown in the prompt.\n"
+#~ "It is possible to enter a ISO date (YYYY-MM-DD) but you won't\n"
+#~ "get a good error response - instead the system tries to interpret\n"
+#~ "the given value as an interval."
+#~ msgstr ""
+#~ "Skriv inn påkrevet verdi som forespurt.\n"
+#~ "Du kan bruke ISO-datoformat (ÅÅÅÅ-MM-DD), men dette gir\n"
+#~ "ingen nyttige feilmeldinger. Systemet prøver i stedet å tolke\n"
+#~ "verdien som et intervall."
 
-#, fuzzy
-#~ msgid "use the default key as default recipient"
-#~ msgstr "hoppet over: offentlig nøkkel allerede satt som standard mottaker\n"
+#~ msgid "Enter the name of the key holder"
+#~ msgstr "Skriv inn navnet på nøkkelholderen"
 
-#, fuzzy
-#~ msgid "force v3 signatures"
-#~ msgstr "sjekke signaturer"
+#~ msgid "please enter an optional but highly suggested email address"
+#~ msgstr "skriv inn en valgfri men anbefalt e-postadresse"
 
-#, fuzzy
-#~ msgid "add this secret keyring to the list"
-#~ msgstr "Trenger den hemmelige nøkkelen for å gjøre dette.\n"
+#~ msgid "Please enter an optional comment"
+#~ msgstr "Skriv inn en valgfri kommentar"
 
-#, fuzzy
-#~ msgid "|N|use compress algorithm N"
-#~ msgstr "ukjent kompresjonsalgoritme"
+#~ msgid ""
+#~ "N  to change the name.\n"
+#~ "C  to change the comment.\n"
+#~ "E  to change the email address.\n"
+#~ "O  to continue with key generation.\n"
+#~ "Q  to quit the key generation."
+#~ msgstr ""
+#~ "N  for å endre navn.\n"
+#~ "C  for å endre kommentar.\n"
+#~ "E  for å endre e-postadresse.\n"
+#~ "O  for å fortsette å lage nøkkel.\n"
+#~ "Q  for å avbryte nøkkel."
 
-#, fuzzy
-#~ msgid "remove key from the public keyring"
-#~ msgstr "fjerne nøkler fra det offentlige nøkkelknippet"
+#~ msgid ""
+#~ "Answer \"yes\" (or just \"y\") if it is okay to generate the sub key."
+#~ msgstr "Svar «ja» (eller bare «j») for å fortsette å lage undernøkkel."
 
 #~ msgid ""
 #~ "When you sign a user ID on a key, you should first verify that the key\n"
@@ -9072,147 +8715,403 @@ msgstr ""
 #~ "\n"
 #~ "If you don't know what the right answer is, answer \"0\"."
 #~ msgstr ""
-#~ "Når du signerer en brukerid på en nøkkel, bør du først bekrefte at\n"
-#~ "nøkkelen tilhører den personen som er angitt i brukeriden.  Det er\n"
-#~ "nyttig for andre å vite hvor nøyaktig du bekreftet dette.\n"
+#~ "Når du signerer en bruker-ID på en nøkkel, bør du først bekrefte at\n"
+#~ "nøkkelen tilhører personen som er valgt i bruker-id-en.  Det er\n"
+#~ "nyttig for andre å vite hvor nøyaktig du kontrollerte dette.\n"
 #~ "\n"
-#~ "\"0\" betyr at du forteller hvor nøye du bekreftet nøkkelen.\n"
+#~ "«0» betyr at du ikke forteller noe om hvor nøye du har kontrollert "
+#~ "nøkkelen.\n"
 #~ "\n"
-#~ "\"1\" betyr at du tror at nøkkelen eies av den personen som påstår å eie\n"
-#~ "    nøkkelen, men du kunne ikke eller bekreftet ikke nøkkelen i det hele\n"
-#~ "    tatt.  Dette er nyttig for en identitetskontroll hvor du signerer\n"
-#~ "    nøkkelen til et pseudonym.\n"
+#~ "«1» betyr at du tror at nøkkelen eies av personen som påstår å eie\n"
+#~ "    den, men du har ikke kontrollert selve nøkkelen i det hele\n"
+#~ "    tatt.  Dette er nyttig ved identitetskontroll hvor du signerer\n"
+#~ "    nøkkelen til et pseudonym.\n"
 #~ "\n"
-#~ "\"2\" betyr at du gjorde en vanlig bekreftelse av nøkkelen.  For "
-#~ "eksempel,\n"
-#~ "    dette kunne bety at du bekreftet nøkkelens fingeravtrykk og sjekket\n"
-#~ "    brukeriden mot et fotografisk id.\n"
+#~ "«2» betyr at du har tatt en enkel kontroll av nøkkelen. For eksempel\n"
+#~ "    kan dette bety at du sjekket nøkkelens fingeravtrykk og\n"
+#~ "    bruker-id-en mot et foto-ID.\n"
 #~ "\n"
-#~ "\"3\" betyr at du gjorde en utfyllende bekreftelse av nøkkelen.  For\n"
-#~ "    eksempel, dette kunne bety at du og eieren av nøkkelen bekreftet\n"
-#~ "    personlig nøkkelens fingeravtrykk og at du sjekket ved hjelp av et\n"
-#~ "    dokument med fotografi som er vanskelig å forfalske at navnet på\n"
-#~ "    nøkkeleieren stemmer med navnet i brukeriden til nøkkelen og til "
-#~ "slutt\n"
-#~ "    at du bekreftet at epostadressen i nøkkelen tilhører nøkkelens eier.\n"
+#~ "«3» betyr at du har kontrollert nøkkelen grundig, for eksempel ved at    "
+#~ "du og nøkkeleieren personlig har bekreftet nøkkelens fingeravtrykk,\n"
+#~ "\v    nøkkelens bruker-ID mot et dokument med med bilde og navn som er\n"
+#~ "\v    vanskelig å forfalske. og at e-postadressen i nøkkelen tilhører "
+#~ "nøkkeleieren.\n"
 #~ "\n"
-#~ "Vær obs på at eksemplene gitt over for nivåene 2 og 3 *bare* er\n"
-#~ "eksempler.  Alt i alt er det opp til deg å bestemme hva «vanlig» og\n"
-#~ "«utfyllende» betyr når du signerer andres nøkler.\n"
+#~ "Vær obs på at eksemplene gitt over for nivåene 2 og 3 *bare* er\n"
+#~ "eksempler. Det er opp til deg Ã¥ bestemme hva Â«enkel» og\n"
+#~ "«grundig» skal bety når du signerer andres nøkler.\n"
 #~ "\n"
-#~ "Svar «0» dersom du ikke vet hva det riktige svaret er."
+#~ "Svar «0» hvis du ikke vet hva som er riktig svar."
+
+#~ msgid "Answer \"yes\" if you want to sign ALL the user IDs"
+#~ msgstr "Svar «ja» hvis du vil signere *alle* bruker-id-ene"
 
-#, fuzzy
 #~ msgid ""
-#~ "please see http://www.gnupg.org/download/iconv.html for more information\n"
-#~ msgstr "vennligst se http://www.gnupg.org/faq.html for mere informasjon\n"
+#~ "Answer \"yes\" if you really want to delete this user ID.\n"
+#~ "All certificates are then also lost!"
+#~ msgstr ""
+#~ "Svar «ja» hvis du er sikker på at du vil slette bruker-id-en.\n"
+#~ "Alle sertifikater går i så fall også tapt."
 
-#, fuzzy
-#~ msgid "please use the script \"%s\" to generate a new key\n"
-#~ msgstr "Vennligst velg hvilken type nøkkel du vil generere:\n"
+#~ msgid "Answer \"yes\" if it is okay to delete the subkey"
+#~ msgstr "Svar «ja» hvis du er sikker på at du vil slette undernøkkelen"
 
-#~ msgid "cipher extension `%s' not loaded due to unsafe permissions\n"
+#~ msgid ""
+#~ "This is a valid signature on the key; you normally don't want\n"
+#~ "to delete this signature because it may be important to establish a\n"
+#~ "trust connection to the key or another key certified by this key."
 #~ msgstr ""
-#~ "cipherutvidelse «%s» ble ikke lastet på grunn av utrygge rettigheter\n"
+#~ "Dette er en gyldig nøkkelsignatur. Du bør normalt\n"
+#~ "ikke slette signaturen, fordi den kan brukes til å koble\n"
+#~ "en troverdighet til enten selve nøkkelen eller en \n"
+#~ "annen nøkkel som denne nøkkelen går god for."
 
-#, fuzzy
-#~ msgid ".\n"
-#~ msgstr "%s.\n"
+#~ msgid ""
+#~ "This signature can't be checked because you don't have the\n"
+#~ "corresponding key.  You should postpone its deletion until you\n"
+#~ "know which key was used because this signing key might establish\n"
+#~ "a trust connection through another already certified key."
+#~ msgstr ""
+#~ "Du mangler nøkkelen som hører til denne signaturen, og\n"
+#~ "kan derfor ikke kontrollere den. Du bør vente med å slette den\n"
+#~ "til du vet hvilken nøkkel som ble brukt, fordi denne signeringsnøkkelen\n"
+#~ "kan være en troverdighetskobling til en annen nøkkel som allerede\n"
+#~ "er bekreftet."
 
-#~ msgid "can't query passphrase in batch mode\n"
-#~ msgstr "kan ikke spørre om passfrase i batchmodus\n"
+#~ msgid ""
+#~ "The signature is not valid.  It does make sense to remove it from\n"
+#~ "your keyring."
+#~ msgstr ""
+#~ "Signaturen er ugyldig. Du bør vurdere å fjerne den\n"
+#~ "fra nøkkelknippet."
 
-#~ msgid "Repeat passphrase: "
-#~ msgstr "Gjenta passfrase: "
+#~ msgid ""
+#~ "This is a signature which binds the user ID to the key. It is\n"
+#~ "usually not a good idea to remove such a signature.  Actually\n"
+#~ "GnuPG might not be able to use this key anymore.  So do this\n"
+#~ "only if this self-signature is for some reason not valid and\n"
+#~ "a second one is available."
+#~ msgstr ""
+#~ "Dette er en signatur som kobler bruker-id-en til nøkkelen.\n"
+#~ "Du bør vanligvis ikke fjerne slike signaturer, fordi GnuPG\n"
+#~ "i så fall ikke kan bruke nøkkelen lenger. Bare gjør dette hvis\n"
+#~ "selvsigneringa er ugyldig av en eller annen grunn, og du\n"
+#~ "har en annen signering tilgjengelig."
 
-#~ msgid "-k[v][v][v][c] [user-id] [keyring]"
-#~ msgstr "-k[v][v][v][c] [brukerid] [nøkkelknippe]"
+#~ msgid ""
+#~ "Change the preferences of all user IDs (or just of the selected ones)\n"
+#~ "to the current list of preferences.  The timestamp of all affected\n"
+#~ "self-signatures will be advanced by one second.\n"
+#~ msgstr ""
+#~ "Endre innstillinger for alle bruker-id-er (eller bare valgte)\n"
+#~ "til gjeldende oppsettsliste. Tidsstempler for alle selvsigneringer\n"
+#~ "blir rykket ett sekund fremover.\n"
 
-#~ msgid "can't gen prime with pbits=%u qbits=%u\n"
-#~ msgstr "kan ikke generere et primtall med pbits=%u qbits=%u\n"
+#~ msgid ""
+#~ "Please repeat the last passphrase, so you are sure what you typed in."
+#~ msgstr "Gjenta siste passordfrase slik at du er sikker på hva du skrev inn."
 
-#~ msgid "can't generate a prime with less than %d bits\n"
-#~ msgstr "kan ikke generere et primtall med mindre enn %d bit\n"
+#~ msgid "Give the name of the file to which the signature applies"
+#~ msgstr "Oppgi navn på fila som signaturen gjelder for"
 
-#~ msgid "no entropy gathering module detected\n"
-#~ msgstr "ingen entropy-innsamlingsmodul ble oppdaget\n"
+#~ msgid "Answer \"yes\" if it is okay to overwrite the file"
+#~ msgstr "Svar «ja» hvis du er sikker på at du vil overskrive fila"
 
-#~ msgid "can't lock `%s': %s\n"
-#~ msgstr "kan ikke låse «%s»: %s\n"
+#~ msgid ""
+#~ "Please enter a new filename. If you just hit RETURN the default\n"
+#~ "file (which is shown in brackets) will be used."
+#~ msgstr ""
+#~ "Skriv inn nytt filnavn. Hvis du bare trykker RETUR, brukes\n"
+#~ "forvalgt filnavn (vist i parentes)."
 
-#~ msgid "`%s' is not a regular file - ignored\n"
-#~ msgstr "«%s» er ikke en vanlig fil - ignorert\n"
+#~ msgid ""
+#~ "You should specify a reason for the certification.  Depending on the\n"
+#~ "context you have the ability to choose from this list:\n"
+#~ "  \"Key has been compromised\"\n"
+#~ "      Use this if you have a reason to believe that unauthorized persons\n"
+#~ "      got access to your secret key.\n"
+#~ "  \"Key is superseded\"\n"
+#~ "      Use this if you have replaced this key with a newer one.\n"
+#~ "  \"Key is no longer used\"\n"
+#~ "      Use this if you have retired this key.\n"
+#~ "  \"User ID is no longer valid\"\n"
+#~ "      Use this to state that the user ID should not longer be used;\n"
+#~ "      this is normally used to mark an email address invalid.\n"
+#~ msgstr ""
+#~ "Du bør oppgi en anledning for sertifiseringa.\n"
+#~ "Velg en passende anledning fra denne lista:\n"
+#~ "  «Nøkkelen er komprommitert»\n"
+#~ "      Velg dette hvis du tror at uautoriserte personer\n"
+#~ "      har fått tilgang til en hemmelige nøkkel.\n"
+#~ "  «Nøkkelen er erstattet»\n"
+#~ "      Velg dette hvis du har erstattet nøkkelen med en ny.\n"
+#~ "  «Nøkkelen er ikke lenger i bruk»\n"
+#~ "      Velg dette hvis du ikke lenger bruker nøkkelen.\n"
+#~ "  «Bruker-ID er ikke lenger gyldig»\n"
+#~ "      Velg dette for å vise at bruker-id-en ikke lenger skal brukes.\n"
+#~ "      Dette brukes vanligvis til å markere en e-postadresse som ugyldig.\n"
 
-#~ msgid "note: random_seed file is empty\n"
-#~ msgstr "merk: random_seed-fila er tom\n"
+#~ msgid ""
+#~ "If you like, you can enter a text describing why you issue this\n"
+#~ "revocation certificate.  Please keep this text concise.\n"
+#~ "An empty line ends the text.\n"
+#~ msgstr ""
+#~ "Hvis du vil, kan du skrive inn en tekst som forklarer hvorfor du\n"
+#~ "utsteder dette opphevelsessertifikatet. Prøv å holde teksten kort.\n"
+#~ "Avslutt med en tom linje.\n"
 
-#~ msgid "can't read `%s': %s\n"
-#~ msgstr "kan ikke lese «%s»: %s\n"
+#~ msgid "create a public key when importing a secret key"
+#~ msgstr "lag en offentlig nøkkel ved importering av hemmelig nøkkel"
 
-#~ msgid "note: random_seed file not updated\n"
-#~ msgstr "merk: random_seed-fila ble ikke oppdatert\n"
+#~ msgid "         algorithms on these user IDs:\n"
+#~ msgstr "         algoritmer på følgende bruker-id-er:\n"
 
-#~ msgid "can't write `%s': %s\n"
-#~ msgstr "kan ikke skrive «%s»: %s\n"
+#~ msgid "key %s: already in secret keyring\n"
+#~ msgstr "nøkkel %s: finnes allerede i hemmelig nøkkelknippe\n"
 
-#~ msgid "WARNING: using insecure random number generator!!\n"
-#~ msgstr "ADVARSEL: bruke usikker tilfeldig-tall-generator!!\n"
+#~ msgid "NOTE: a key's S/N does not match the card's one\n"
+#~ msgstr "MERK: serienummer for en nøkkel samsvarer ikke med nummer på kort\n"
+
+#~ msgid "NOTE: primary key is online and stored on card\n"
+#~ msgstr "MERK: primærnøkkel er på nett og lagret på kort\n"
+
+#~ msgid "NOTE: secondary key is online and stored on card\n"
+#~ msgstr "MERK: sekundærnøkkel er på nett og lagret på kort\n"
+
+#~ msgid "%d signatures not checked due to missing keys\n"
+#~ msgstr "%d signaturer ble ikke sjekket på grunn av manglende nøkler\n"
+
+#~ msgid "%d signatures not checked due to errors\n"
+#~ msgstr "%d signaturer ble ikke sjekket på grunn av feil\n"
+
+#~ msgid "1 user ID without valid self-signature detected\n"
+#~ msgstr "oppdaget 1 bruker-ID uten gyldig selvsignatur\n"
 
 #~ msgid ""
-#~ "The random number generator is only a kludge to let\n"
-#~ "it run - it is in no way a strong RNG!\n"
-#~ "\n"
-#~ "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n"
+#~ "You may not make an OpenPGP signature on a PGP 2.x key while in --pgp2 "
+#~ "mode.\n"
+#~ msgstr ""
+#~ "Du kan ikke lage OpenPGP-signatur på en PGP-2.x-nøkkel i «--pgp2»-modus.\n"
+
+#~ msgid "This would make the key unusable in PGP 2.x.\n"
+#~ msgstr "Dette ville gjøre nøkkelen ubrukelig i PGP 2.x.\n"
+
+#~ msgid "This key is not protected.\n"
+#~ msgstr "Denne nøkkelen er ikke beskyttet.\n"
+
+#~ msgid "Key is protected.\n"
+#~ msgstr "Nøkkelen er beskyttet.\n"
+
+#~ msgid "Can't edit this key: %s\n"
+#~ msgstr "Klarte ikke å redigere denne nøkkelen: %s\n"
+
+#~ msgid ""
+#~ "Enter the new passphrase for this secret key.\n"
 #~ "\n"
 #~ msgstr ""
-#~ "Denne tilfeldig-tall-generatoren er bare en omvei for å få programmet\n"
-#~ "til å kjøre - den er på ingen måte en sterk RNG!\n"
+#~ "Skriv inn ny passordfrase for denne hemmelige nøkklen.\n"
 #~ "\n"
-#~ "IKKE BRUK NOE DATA GENERERT AV DETTE PROGRAMMET!!\n"
+
+#~ msgid "passphrase not correctly repeated; try again"
+#~ msgstr "passordfrasen ble ikke gjentatt korrekt. Prøv igjen"
 
 #~ msgid ""
-#~ "Please wait, entropy is being gathered. Do some work if it would\n"
-#~ "keep you from getting bored, because it will improve the quality\n"
-#~ "of the entropy.\n"
+#~ "You don't want a passphrase - this is probably a *bad* idea!\n"
+#~ "\n"
 #~ msgstr ""
-#~ "Vennligst vent, entropy blir innsamlet.  Gjør noe arbeid dersom det\n"
-#~ "hindrer deg fra å kjede deg, fordi arbeidet vil forbedre kvaliteten på\n"
-#~ "entropyen.\n"
+#~ "Du har ikke valgt en passordfrase. Dette er sannsynligvis *ikke* lurt.\n"
+#~ "\n"
+
+#~ msgid "Do you really want to do this? (y/N) "
+#~ msgstr "Er du sikker på at du vil gjøre dette? (j/N) "
+
+#~ msgid "toggle between the secret and public key listings"
+#~ msgstr "veksle mellom hemmelig og offentlig nøkkellisting"
+
+#~ msgid "error reading secret keyblock \"%s\": %s\n"
+#~ msgstr "feil under lesing av hemmelig nøkkelblokk «%s». %s\n"
+
+#~ msgid "Please use the command \"toggle\" first.\n"
+#~ msgstr "Bruk kommandoen «toggle» først.\n"
+
+#~ msgid "Deleted %d signatures.\n"
+#~ msgstr "Slettet %d signaturer.\n"
+
+#~ msgid "User ID \"%s\": %d signatures removed\n"
+#~ msgstr "Bruker-ID «%s»: %d signaturer fjernet\n"
+
+#~ msgid "Please remove selections from the secret keys.\n"
+#~ msgstr "Fjern utvalget fra de hemmelige nøklene.\n"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Velg minst én undernøkkel.\n"
+
+#~ msgid "No corresponding signature in secret ring\n"
+#~ msgstr "Ingen samsvarende signatur på hemmelig nøkkelknippe\n"
+
+#~ msgid "%s.\n"
+#~ msgstr "%s.\n"
 
 #~ msgid ""
+#~ "You don't want a passphrase - this is probably a *bad* idea!\n"
+#~ "I will do it anyway.  You can change your passphrase at any time,\n"
+#~ "using this program with the option \"--edit-key\".\n"
 #~ "\n"
-#~ "Not enough random bytes available.  Please do some other work to give\n"
-#~ "the OS a chance to collect more entropy! (Need %d more bytes)\n"
 #~ msgstr ""
+#~ "Du har ikke valgt en passordfrase. Dette er sannsynligvis *ikke* lurt.\n"
+#~ "Jeg fortsetter likevel. Du kan endre passordfrasen når som helst ved\n"
+#~ "å bruke valget «--edit-key».\n"
 #~ "\n"
-#~ "Ikke nok tilfeldige byter tilgjengelig.  Vennligst gjør noe annet\n"
-#~ "arbeid for å gi operativsystemet en sjanse til å samle mer entropy!\n"
-#~ "(Trenger %d flere byter)\n"
 
-#, fuzzy
-#~ msgid "card reader not available\n"
-#~ msgstr "hemmelig nøkkel er ikke tilgjengelig"
+#~ msgid "writing secret key stub to `%s'\n"
+#~ msgstr "skriver foreløpig hemmelig nøkkel til «%s»\n"
 
-#~ msgid "Please insert the card and hit return or enter 'c' to cancel: "
+#~ msgid "storing key onto card failed: %s\n"
+#~ msgstr "lagring av nøkkel på kort mislyktes: %s\n"
+
+#~ msgid "WARNING: 2 files with confidential information exists.\n"
+#~ msgstr "ADVARSEL: 2 filer med konfidensiell informasjon finnes.\n"
+
+#~ msgid "%s is the unchanged one\n"
+#~ msgstr "%s er uendret\n"
+
+#~ msgid "%s is the new one\n"
+#~ msgstr "%s er ny\n"
+
+#~ msgid "Please fix this possible security flaw\n"
+#~ msgstr "Du bør fikse denne potensielle sikkerhetsrisikoen\n"
+
+#~ msgid "%lu keys cached (%lu signatures)\n"
+#~ msgstr "%lu nøkler hurtiglagret (%lu signaturer)\n"
+
+#~ msgid "use temporary files to pass data to keyserver helpers"
 #~ msgstr ""
-#~ "Vennligst sett inn kortet og trykk på enter eller tast inn «c» for å "
-#~ "avbryte: "
+#~ "bruk midlertidige filer for å overføre data til nøkkeltjener-hjelpere"
 
-#~ msgid "Hit return when ready or enter 'c' to cancel: "
-#~ msgstr "Trykk på enter når du er klar eller tast «c» for å avbryte: "
+#~ msgid "do not delete temporary files after using them"
+#~ msgstr "ikke slett midlertidige filer etter å ha brukt dem"
 
-#~ msgid "Enter New Admin PIN: "
-#~ msgstr "Tast inn ny Admin-PIN: "
+#~ msgid "WARNING: keyserver option `%s' is not used on this platform\n"
+#~ msgstr ""
+#~ "ADVARSEL: nøkkeltjener-valget «%s» er ikke i bruk på denne plattformen\n"
 
-#~ msgid "Enter New PIN: "
-#~ msgstr "Tast inn ny PIN: "
+#~ msgid "searching for names from %s server %s\n"
+#~ msgstr "søker etter navn fra %s tjener %s\n"
 
-#~ msgid "Enter Admin PIN: "
-#~ msgstr "Tast inn Admin-PIN: "
+#~ msgid "searching for names from %s\n"
+#~ msgstr "søker etter navn fra %s\n"
 
-#, fuzzy
-#~ msgid "         algorithms on these user IDs:\n"
-#~ msgstr "                nye brukerider: %lu\n"
+#~ msgid "searching for \"%s\" from %s server %s\n"
+#~ msgstr "søker etter «%s» fra %s tjener %s\n"
+
+#~ msgid "searching for \"%s\" from %s\n"
+#~ msgstr "søker etter «%s» fra %s\n"
+
+#~ msgid "WARNING: keyserver handler from a different version of GnuPG (%s)\n"
+#~ msgstr ""
+#~ "ADVARSEL: nøkkeltjener-behandler er av en annen GnuPG-versjon (%s)\n"
+
+#~ msgid "keyserver did not send VERSION\n"
+#~ msgstr "nøkkeltjener sendte ikke «VERSION»\n"
+
+#~ msgid "keyserver communications error: %s\n"
+#~ msgstr "kommunikasjonsfeil med nøkkeltjener: %s\n"
+
+#~ msgid "external keyserver calls are not supported in this build\n"
+#~ msgstr ""
+#~ "eksterne nøkkeltjener-kall støttes ikke av denne programinstallasjonen\n"
+
+#~ msgid "no handler for keyserver scheme `%s'\n"
+#~ msgstr "ingen behandler for nøkkeltjener-skjema «%s»\n"
+
+#~ msgid "action `%s' not supported with keyserver scheme `%s'\n"
+#~ msgstr "handlinga «%s» støttes ikke med nøkkeltjener-skjema «%s»\n"
+
+#~ msgid "%s does not support handler version %d\n"
+#~ msgstr "%s støtter ikke behandlerversjon %d\n"
+
+#~ msgid "keyserver timed out\n"
+#~ msgstr "tidsavbrudd for nøkkeltjener\n"
+
+#~ msgid "keyserver internal error\n"
+#~ msgstr "intern feil på nøkkeltjener\n"
+
+#~ msgid "refreshing 1 key from %s\n"
+#~ msgstr "oppfrisker 1 nøkkel fra %s\n"
+
+#~ msgid "WARNING: unable to parse URI %s\n"
+#~ msgstr "ADVARSEL: klarte ikke å tolke adressen %s\n"
+
+#~ msgid "invalid root packet detected in proc_tree()\n"
+#~ msgstr "fant ugyldig rotpakke i proc_tree()\n"
+
+#~ msgid "NOTE: This feature is not available in %s\n"
+#~ msgstr "MERK: Denne funksjonen er ikke tilgjengelig i %s\n"
+
+#~ msgid "malformed GPG_AGENT_INFO environment variable\n"
+#~ msgstr "miljøvariabelen «GPG_AGENT_INFO» er feilformatert\n"
+
+#~ msgid "Repeat passphrase\n"
+#~ msgstr "Gjenta passordfrase\n"
+
+#~ msgid "can't query passphrase in batch mode\n"
+#~ msgstr "du kan ikke spørre om passordfrase i buntmodus\n"
+
+#~ msgid "Repeat passphrase: "
+#~ msgstr "Gjenta passordfrase: "
+
+#~ msgid "no photo viewer set\n"
+#~ msgstr "ingen bildefremviser valgt\n"
+
+#~ msgid "no corresponding public key: %s\n"
+#~ msgstr "ingen motsvarende offentlig nøkkel: %s\n"
+
+#~ msgid "public key does not match secret key!\n"
+#~ msgstr "offentlig nøkkel samsvarer ikke med hemmelig nøkkel.\n"
+
+#~ msgid "unknown protection algorithm\n"
+#~ msgstr "ukjent beskyttelsesalgoritme\n"
+
+#~ msgid "NOTE: This key is not protected!\n"
+#~ msgstr "MERK: denne nøkkelen er ikke beskyttet.\n"
+
+#~ msgid "Invalid passphrase; please try again"
+#~ msgstr "Ugyldig passordfrase. Prøv igjen"
+
+#~ msgid "%s ...\n"
+#~ msgstr "%s …\n"
+
+#~ msgid "WARNING: Weak key detected - please change passphrase again.\n"
+#~ msgstr "ADVARSEL: Oppdaget svak nøkkel. Du bør endre passordfrasen igjen.\n"
+
+#~ msgid ""
+#~ "generating the deprecated 16-bit checksum for secret key protection\n"
+#~ msgstr ""
+#~ "lager utgått 16-bit-kontrollsum for beskyttelse av hemmelig nøkkel\n"
+
+#~ msgid "public key %s is %lu seconds newer than the signature\n"
+#~ msgstr "offentlig nøkkel %s er %lu sekunder nyere enn signaturen\n"
+
+#~ msgid ""
+#~ "key %s was created %lu seconds in the future (time warp or clock "
+#~ "problem)\n"
+#~ msgstr ""
+#~ "nøkkel %s ble opprettet %lu sekunder i fremtiden (tidsforskyvnings- eller "
+#~ "klokkeproblem)\n"
+
+#~ msgid ""
+#~ "you can only detach-sign with PGP 2.x style keys while in --pgp2 mode\n"
+#~ msgstr ""
+#~ "du må bruke «--pgp2»-modus for å signere adskilt med PGP 2.x-nøkler\n"
+
+#~ msgid ""
+#~ "you can only clearsign with PGP 2.x style keys while in --pgp2 mode\n"
+#~ msgstr ""
+#~ "du må bruke «--pgp2»-modus for å signere i klartekst med PGP 2.x-nøkler\n"
+
+#~ msgid "%d marginal(s) needed, %d complete(s) needed, %s trust model\n"
+#~ msgstr ""
+#~ "%d marginal(er) nødvendig, %d fullstendig(e) nødvendig, tillitsmodell %s\n"
 
 #~ msgid "general error"
 #~ msgstr "generell feil"
@@ -9221,13 +9120,13 @@ msgstr ""
 #~ msgstr "ukjent pakketype"
 
 #~ msgid "unknown digest algorithm"
-#~ msgstr "ukjent digest-algoritme"
+#~ msgstr "ukjent kontrollsum-algoritme"
 
 #~ msgid "bad public key"
-#~ msgstr "ugyldig offentlig nøkkel"
+#~ msgstr "ugyldig offentlig nøkkel"
 
 #~ msgid "bad secret key"
-#~ msgstr "ugyldig hemmelig nøkkel"
+#~ msgstr "ugyldig hemmelig nøkkel"
 
 #~ msgid "bad signature"
 #~ msgstr "ugyldig signatur"
@@ -9235,53 +9134,62 @@ msgstr ""
 #~ msgid "checksum error"
 #~ msgstr "sjekksumfeil"
 
+#~ msgid "can't open the keyring"
+#~ msgstr "klarte ikke å åpne nøkkelknippe"
+
 #~ msgid "invalid packet"
 #~ msgstr "ugyldig pakke"
 
+#~ msgid "invalid armor"
+#~ msgstr "ugyldig beskyttelse"
+
 #~ msgid "no such user id"
-#~ msgstr "det finnes ingen slik brukerid"
+#~ msgstr "bruker-id-en finnes ikke"
 
 #~ msgid "wrong secret key used"
-#~ msgstr "feil hemmelig nøkkel ble brukt"
+#~ msgstr "feil hemmelig nøkkel ble brukt"
 
 #~ msgid "file write error"
-#~ msgstr "feil ved skriving av fil"
+#~ msgstr "feil under skriving av fil"
+
+#~ msgid "unknown compress algorithm"
+#~ msgstr "ukjent komprimeringsalgoritme"
 
 #~ msgid "file open error"
-#~ msgstr "feil ved åpning av fil"
+#~ msgstr "feil under åpning av fil"
 
 #~ msgid "file create error"
-#~ msgstr "feil ved opprettelse av fil"
+#~ msgstr "feil under opprettelse av fil"
 
 #~ msgid "unimplemented pubkey algorithm"
 #~ msgstr "uimplementert pubkey-algoritme"
 
 #~ msgid "unimplemented cipher algorithm"
-#~ msgstr "uimplementert kryptoalgoritme"
+#~ msgstr "uimplementert krypteringsalgoritme"
 
 #~ msgid "unknown signature class"
 #~ msgstr "ukjent signaturklasse"
 
 #~ msgid "trust database error"
-#~ msgstr "feil med tillitsdatabasen"
+#~ msgstr "feil med tillitsdatabase"
 
 #~ msgid "resource limit"
 #~ msgstr "ressursgrense"
 
 #~ msgid "invalid keyring"
-#~ msgstr "ugyldig nøkkelknippe"
+#~ msgstr "ugyldig nøkkelknippe"
 
 #~ msgid "malformed user id"
-#~ msgstr "vansired brukerid"
+#~ msgstr "feilformatert bruker-ID"
 
 #~ msgid "file close error"
-#~ msgstr "feil ved lukking av fil"
+#~ msgstr "feil under lukking av fil"
 
 #~ msgid "file rename error"
-#~ msgstr "feil ved omdøping av fil"
+#~ msgstr "feil under fil-navnebytte"
 
 #~ msgid "file delete error"
-#~ msgstr "feil ved sletting av fil"
+#~ msgstr "feil under sletting av fil"
 
 #~ msgid "unexpected data"
 #~ msgstr "uforventet data"
@@ -9293,10 +9201,10 @@ msgstr ""
 #~ msgstr "ubrukelig pubkey algoritme"
 
 #~ msgid "file exists"
-#~ msgstr "fila finnes fra før av"
+#~ msgstr "fila finnes fra før av"
 
 #~ msgid "weak key"
-#~ msgstr "svak nøkkel"
+#~ msgstr "svak nøkkel"
 
 #~ msgid "bad URI"
 #~ msgstr "ugyldig URI"
@@ -9308,19 +9216,34 @@ msgstr ""
 #~ msgstr "ikke behandlet"
 
 #~ msgid "unusable public key"
-#~ msgstr "ubrukelig offentlig nøkkel"
+#~ msgstr "ubrukelig offentlig nøkkel"
+
+#~ msgid "unusable secret key"
+#~ msgstr "ubrukelig hemmelig nøkkel"
 
 #~ msgid "keyserver error"
-#~ msgstr "feil med nøkkelserver"
+#~ msgstr "feil på nøkkeltjener"
+
+#~ msgid "no card"
+#~ msgstr "ingen kort"
 
 #~ msgid "no data"
 #~ msgstr "ingen data"
 
+#~ msgid "ERROR: "
+#~ msgstr "FEIL: "
+
 #~ msgid "... this is a bug (%s:%d:%s)\n"
-#~ msgstr "... dette er en feil (%s:%d:%s)\n"
+#~ msgstr "… dette er en feil (%s:%d:%s)\n"
+
+#~ msgid ""
+#~ "please see http://www.gnupg.org/documentation/faqs.html for more "
+#~ "information\n"
+#~ msgstr ""
+#~ "se http://www.gnupg.org/documentation/faq.html for mer informasjon\n"
 
 #~ msgid "operation is not possible without initialized secure memory\n"
-#~ msgstr "operasjonen er ikke mulig uten initialisert sikkert minne\n"
+#~ msgstr "handlinga kan ikke utføres uten sikkert minne\n"
 
 #~ msgid "(you may have used the wrong program for this task)\n"
-#~ msgstr "(du kan ha brukt feil program for denne oppgaven)\n"
+#~ msgstr "(du kan ha brukt feil program til denne oppgaven)\n"
index 075ec76..74cd6d9 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -1803,6 +1803,15 @@ msgstr "usuni
 msgid " - skipped"
 msgstr "%s: pominiêty: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "zapis do ,,%s''\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "klucz %s: zawarto¶æ klucza na karcie - pominiêto\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "eksport kluczy tajnych nie jest dozwolony\n"
 
@@ -1810,10 +1819,6 @@ msgstr "eksport kluczy tajnych nie jest dozwolony\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "klucz %s: klucz PGP 2.x - pominiêty\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "klucz %s: zawarto¶æ klucza na karcie - pominiêto\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "OSTRZE¯ENIE: nic nie zosta³o wyeksportowane!\n"
 
@@ -1933,6 +1938,11 @@ msgstr "generacja nowej pary kluczy"
 msgid "quickly add a new user-id"
 msgstr "generacja nowej pary kluczy"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "generacja nowej pary kluczy"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2304,6 +2314,11 @@ msgstr "%s:%d: niepoprawne opcje wczytania kluczy\n"
 msgid "invalid import options\n"
 msgstr "niepoprawne opcje wczytania kluczy\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "niepoprawne opcje wypisywania\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d niepoprawne opcje eksportu kluczy\n"
@@ -2636,6 +2651,11 @@ msgstr "nie uaktualnianie bazy zaufania po imporcie"
 msgid "do not update the trustdb after import"
 msgstr "nie uaktualnianie bazy zaufania po imporcie"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "okazanie odcisku klucza"
+
 msgid "only accept updates to existing keys"
 msgstr "przyjmowanie tylko uaktualnieñ istniej±cych kluczy"
 
@@ -2645,6 +2665,9 @@ msgstr "usuwanie bezu
 msgid "remove as much as possible from key after import"
 msgstr "usuwanie jak najwiêkszej czê¶ci kluczy po imporcie"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "blok typu %d zostaje pominiêty\n"
@@ -2789,11 +2812,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "brak zapisywalnego zbioru kluczy: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "zapis do ,,%s''\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "b³±d zapisu zbioru kluczy ,,%s'': %s\n"
@@ -3577,6 +3595,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Klucz nie zosta³ zmieniony wiêc zapis zmian nie jest konieczny.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Generacja klucza nie powiod³a siê: %s\n"
+
+#, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "niew³a¶ciwy odcisk"
@@ -3898,6 +3921,10 @@ msgid "no secret key\n"
 msgstr "brak klucza tajnego\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "identyfikator u¿ytkownika ,,%s'' zosta³ ju¿ uniewa¿niony\n"
 
@@ -4441,10 +4468,6 @@ msgstr[2] ""
 msgid "Keyring"
 msgstr "Zbiór kluczy"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "pominiêty ,,%s'': %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Odcisk klucza g³ównego:"
 
@@ -4568,6 +4591,10 @@ msgid "no keyserver known\n"
 msgstr "brak akcji serwera kluczy!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "pominiêty ,,%s'': %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "wysy³anie klucza %s na %s\n"
 
index e20d484..beee02b 100644 (file)
--- a/po/pt.po
+++ b/po/pt.po
@@ -1785,6 +1785,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: ignorado: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "a escrever para `%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "chave %08lX: assintura da subchave no local errado - ignorado\n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "a escrever chave privada para `%s'\n"
@@ -1793,10 +1802,6 @@ msgstr "a escrever chave privada para `%s'\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "chave %08lX: tipo PGP 2.x - ignorada\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "chave %08lX: assintura da subchave no local errado - ignorado\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "AVISO: nada exportado\n"
 
@@ -1916,6 +1921,11 @@ msgstr "gerar um novo par de chaves"
 msgid "quickly add a new user-id"
 msgstr "gerar um novo par de chaves"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "gerar um novo par de chaves"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2256,6 +2266,10 @@ msgstr "%s:%d: op
 msgid "invalid import options\n"
 msgstr "opções de importação inválidas\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "opções de importação inválidas\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: opções de exportação inválidas\n"
@@ -2595,6 +2609,10 @@ msgstr "actualizar a base de dados de confian
 msgid "do not update the trustdb after import"
 msgstr "actualizar a base de dados de confiança"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "mostra impressão digital"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2605,6 +2623,9 @@ msgstr "chave secreta n
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "ignorando bloco do tipo %d\n"
@@ -2745,11 +2766,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "não foi encontrada nenhum porta-chaves onde escrever: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "a escrever para `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "erro na escrita do porta-chaves `%s': %s\n"
@@ -3544,6 +3560,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Chave não alterada, nenhuma actualização é necessária.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "A geração de chaves falhou: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "%s: versão de ficheiro inválida %d\n"
 
@@ -3866,6 +3887,10 @@ msgid "no secret key\n"
 msgstr "nenhuma chave secreta\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "o utilizador com o id \"%s\" já está revocado\n"
 
@@ -4397,10 +4422,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Porta-chaves"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "ignorado `%s': %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Impressão da chave primária:"
 
@@ -4520,6 +4541,10 @@ msgid "no keyserver known\n"
 msgstr "opções de exportação inválidas\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "ignorado `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 9f54576..71435aa 100644 (file)
--- a/po/ro.po
+++ b/po/ro.po
@@ -1788,6 +1788,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: sãritã: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "scriu în `%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "cheia %s: semnãturã subcheie într-un loc greºit - sãritã\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "exportul cheilor secrete nu este permis\n"
 
@@ -1795,10 +1804,6 @@ msgstr "exportul cheilor secrete nu este permis\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "cheia %s: cheie stil PGP 2.x - sãritã\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "cheia %s: semnãturã subcheie într-un loc greºit - sãritã\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "AVERTISMENT: nimic exportat\n"
 
@@ -1916,6 +1921,11 @@ msgstr "genereaz
 msgid "quickly add a new user-id"
 msgstr "genereazã o nouã perechi de chei"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "genereazã o nouã perechi de chei"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2287,6 +2297,11 @@ msgstr "%s:%d: op
 msgid "invalid import options\n"
 msgstr "opþiuni import invalide\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "opþiuni enumerare invalide\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: opþiuni export invalide\n"
@@ -2622,6 +2637,11 @@ msgstr "actualizeaz
 msgid "do not update the trustdb after import"
 msgstr "actualizeazã baza de date de încredere"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "afiºeazã amprenta cheii"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2632,6 +2652,9 @@ msgstr "cheie secret
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "bloc de tip %d sãrit\n"
@@ -2776,11 +2799,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "n-am gãsit nici un inel de chei ce poate fi scris: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "scriu în `%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "eroare la scrierea inelului de chei `%s': %s\n"
@@ -3542,6 +3560,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Cheia nu a fost schimbatã aºa cã nici o actualizare a fost necesarã.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Generarea cheii a eºuat: %s\n"
+
+#, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "amprentã invalidã"
@@ -3868,6 +3891,11 @@ msgstr "Dori
 msgid "no secret key\n"
 msgstr "nici o cheie secretã\n"
 
+#, fuzzy, c-format
+#| msgid "revoke a user ID"
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr "revocã un ID utilizator"
+
 #, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "ID-ul utilizator \"%s\" este deja revocat\n"
@@ -4393,10 +4421,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Inel de chei"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "sãritã \"%s\": %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Amprentã cheie primarã:"
 
@@ -4517,6 +4541,10 @@ msgid "no keyserver known\n"
 msgstr "nici o acþiune pentru serverul de chei!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "sãritã \"%s\": %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "trimit cheia %s lui %s\n"
 
@@ -10306,9 +10334,6 @@ msgstr ""
 #~ msgid "revuid"
 #~ msgstr "revuid"
 
-#~ msgid "revoke a user ID"
-#~ msgstr "revocã un ID utilizator"
-
 #~ msgid "revkey"
 #~ msgstr "revkey"
 
index 7997837..57c4045 100644 (file)
--- a/po/ru.po
+++ b/po/ru.po
@@ -11,7 +11,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: GnuPG 2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2016-01-27 17:17+0000\n"
+"PO-Revision-Date: 2016-06-20 17:17+0000\n"
 "Last-Translator: Ineiev <ineiev@gnu.org>\n"
 "Language-Team: Russian <gnupg-ru@gnupg.org>\n"
 "Language: ru\n"
@@ -1666,6 +1666,14 @@ msgstr "при экспорте удалить из ключа как можно
 msgid " - skipped"
 msgstr " - пропущено"
 
+#, c-format
+msgid "writing to '%s'\n"
+msgstr "сохраняю в '%s'\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "ключ %s: материал ключа на карте - пропущен\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "экспорт секретных ключей не разрешен\n"
 
@@ -1673,10 +1681,6 @@ msgstr "экспорт секретных ключей не разрешен\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "ключ %s: ключ типа PGP 2.x - пропущен\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "ключ %s: материал ключа на карте - пропущен\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "Внимание: нечего экспортировать\n"
 
@@ -1788,6 +1792,11 @@ msgstr "быстро создать новую пару ключей"
 msgid "quickly add a new user-id"
 msgstr "быстро добавить новый ID пользователя"
 
+#, fuzzy
+#| msgid "quickly add a new user-id"
+msgid "quickly revoke a user-id"
+msgstr "быстро добавить новый ID пользователя"
+
 msgid "full featured key pair generation"
 msgstr "создание полноценной пары ключей"
 
@@ -2107,6 +2116,11 @@ msgstr "%s:%d: недопустимые параметры импорта\n"
 msgid "invalid import options\n"
 msgstr "недопустимые параметры импорта\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "недопустимые параметры списка\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: недопустимые параметры экспорта\n"
@@ -2395,7 +2409,7 @@ msgid "|FD|write status info to this FD"
 msgstr "|FD|выводить информацию в файл с дескриптором FD"
 
 msgid "|ALGO|reject signatures made with ALGO"
-msgstr ""
+msgstr "|ALGO|отвергать подписи, сделанные по данному алгоритму"
 
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Вызов: gpgv [параметры] [файлы] (-h для подсказки)"
@@ -2426,6 +2440,11 @@ msgstr "не сбрасывать уровни доверия владельца
 msgid "do not update the trustdb after import"
 msgstr "не обновлять таблицу доверия после импорта"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "показать отпечаток ключа"
+
 msgid "only accept updates to existing keys"
 msgstr "обновлять только существующие ключи"
 
@@ -2435,6 +2454,9 @@ msgstr "удалить после импорта непригодные част
 msgid "remove as much as possible from key after import"
 msgstr "удалить после импорта из ключа как можно больше"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "пропущен блок типа %d\n"
@@ -2578,10 +2600,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "нет доступной для записи таблицы ключей: %s\n"
 
 #, c-format
-msgid "writing to '%s'\n"
-msgstr "сохраняю в '%s'\n"
-
-#, c-format
 msgid "error writing keyring '%s': %s\n"
 msgstr "ошибка записи таблицы ключей '%s': %s\n"
 
@@ -3310,6 +3328,11 @@ msgstr "сбой при обновлении: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "Ключ не изменялся - обновление не нужно.\n"
 
+#, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Сбой при создании ключа: %s\n"
+
 #, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\" - не отпечаток\n"
@@ -3620,6 +3643,10 @@ msgid "no secret key\n"
 msgstr "нет секретного ключа\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "ID пользователя \"%s\" уже отозван\n"
 
@@ -4126,10 +4153,6 @@ msgstr[2] "Внимание: %lu ключей пропущено из-за бо
 msgid "Keyring"
 msgstr "Таблица ключей"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "пропущено \"%s\": %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Отпечаток первичного ключа:"
 
@@ -4247,6 +4270,10 @@ msgid "no keyserver known\n"
 msgstr "ни один сервер ключей не известен\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "пропущено \"%s\": %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "отправка ключа %s на %s\n"
 
@@ -5812,10 +5839,8 @@ msgstr "[ неизвестно ]"
 msgid "[  undef ]"
 msgstr "[неопределено]"
 
-#, fuzzy
-#| msgid "never"
 msgid "[  never ]"
-msgstr "никогда"
+msgstr "[   никогда  ]"
 
 msgid "[marginal]"
 msgstr "[ ограничено ]"
index bf23106..8dda2be 100644 (file)
--- a/po/sk.po
+++ b/po/sk.po
@@ -1789,6 +1789,15 @@ msgstr ""
 msgid " - skipped"
 msgstr "%s: preskoèené: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "zapisujem do '%s'\n"
+
+#, fuzzy, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "kµúè %08lX: podpis subkµúèa na zlom mieste - preskoèené \n"
+
 #, fuzzy
 msgid "exporting secret keys not allowed\n"
 msgstr "zapisujem tajný kµúè do `%s'\n"
@@ -1797,10 +1806,6 @@ msgstr "zapisujem tajn
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "kµúè %08lX: PGP 2.x kµúè - preskoèené\n"
 
-#, fuzzy, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "kµúè %08lX: podpis subkµúèa na zlom mieste - preskoèené \n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "VAROVANIE: niè nebolo vyexportované\n"
 
@@ -1922,6 +1927,11 @@ msgstr "vytvori
 msgid "quickly add a new user-id"
 msgstr "vytvori» nový pár kµúèov"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "vytvori» nový pár kµúèov"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2266,6 +2276,10 @@ msgstr "%s:%d: neplatn
 msgid "invalid import options\n"
 msgstr "neplatný parameter pre import\n"
 
+#, fuzzy, c-format
+msgid "invalid filter option: %s\n"
+msgstr "neplatný parameter pre import\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: neplatný parameter pre export\n"
@@ -2607,6 +2621,10 @@ msgstr "aktualizova
 msgid "do not update the trustdb after import"
 msgstr "aktualizova» databázu dôvery"
 
+#, fuzzy
+msgid "show key during import"
+msgstr "vypísa» fingerprint"
+
 msgid "only accept updates to existing keys"
 msgstr ""
 
@@ -2617,6 +2635,9 @@ msgstr "nepou
 msgid "remove as much as possible from key after import"
 msgstr ""
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "blok typu %d bol preskoèený\n"
@@ -2759,11 +2780,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "nenájdený zapisovateµný súbor kµúèov (keyring): %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "zapisujem do '%s'\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "chyba pri zápise súboru kµúèov (keyring)  `%s': %s\n"
@@ -3555,6 +3571,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "kµúè nebol zmenený, tak¾e nie je potrebné ho aktualizova».\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Vytvorenie kµúèa sa nepodarilo: %s\n"
+
+#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "chyba: neplatný odtlaèok\n"
 
@@ -3877,6 +3898,10 @@ msgid "no secret key\n"
 msgstr "neexistuje tajný kµúè\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "u¾ívateµské ID \"%s\" je u¾ revokované\n"
 
@@ -4402,10 +4427,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "súbor kµúèov (keyring)"
 
-#, fuzzy, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "preskoèený `%s': %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Primárny fingerprint kµúèa:"
 
@@ -4525,6 +4546,10 @@ msgid "no keyserver known\n"
 msgstr "neplatný parameter pre export\n"
 
 #, fuzzy, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "preskoèený `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "sending key %s to %s\n"
 msgstr ""
 "\"\n"
index 996912a..5c41560 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -1851,6 +1851,15 @@ msgstr "ta bort så mycket som möjligt från nyckeln under exportering"
 msgid " - skipped"
 msgstr "%s: hoppade över: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "skriver till \"%s\"\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "nyckeln %s: nyckelmaterial på kortet - hoppade över\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "export av hemliga nycklar tillåts inte\n"
 
@@ -1858,10 +1867,6 @@ msgstr "export av hemliga nycklar tillåts inte\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "nyckeln %s: nyckel av PGP 2.x-typ - hoppade över\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "nyckeln %s: nyckelmaterial på kortet - hoppade över\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "VARNING: ingenting exporterat\n"
 
@@ -1982,6 +1987,11 @@ msgstr "generera ett nytt nyckelpar"
 msgid "quickly add a new user-id"
 msgstr "generera ett nytt nyckelpar"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "generera ett nytt nyckelpar"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2344,6 +2354,11 @@ msgstr "%s:%d: ogiltiga importeringsflaggor\n"
 msgid "invalid import options\n"
 msgstr "ogiltiga importflaggor\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "ogiltiga listflaggor\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: ogiltiga exportflaggor\n"
@@ -2687,6 +2702,11 @@ msgstr "uppdatera inte tillitsdatabasen efter importering"
 msgid "do not update the trustdb after import"
 msgstr "uppdatera inte tillitsdatabasen efter importering"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "visa nyckelns fingeravtryck"
+
 msgid "only accept updates to existing keys"
 msgstr "acceptera endast uppdateringar till befintliga nycklar"
 
@@ -2696,6 +2716,9 @@ msgstr "ta bort oanvändbara delar från nyckeln efter importering"
 msgid "remove as much as possible from key after import"
 msgstr "ta bort så mycket som möjligt från nyckeln efter importering"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "hoppar över block av typen %d\n"
@@ -2844,11 +2867,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "hittade ingen nyckelring som gick att skriva till: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "skriver till \"%s\"\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "fel vid skrivning av nyckelringen \"%s\": %s\n"
@@ -3620,6 +3638,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Nyckeln är oförändrad så det behövs ingen uppdatering.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Nyckelgenereringen misslyckades: %s\n"
+
+#, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "ogiltigt fingeravtryck"
@@ -3948,6 +3971,10 @@ msgid "no secret key\n"
 msgstr "ingen hemlig nyckel\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "användaridentiteten \"%s\" är redan spärrad\n"
 
@@ -4488,10 +4515,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Nyckelring"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "hoppade över \"%s\": %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Primära nyckelns fingeravtryck:"
 
@@ -4611,6 +4634,10 @@ msgid "no keyserver known\n"
 msgstr "ingen nyckelserveråtgärd!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "hoppade över \"%s\": %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "skickar nyckeln %s till %s\n"
 
index c40022d..6e661b5 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -1797,6 +1797,15 @@ msgstr "ihraç sırasında anahtardan mümkün olduğunca çok şey kaldırılı
 msgid " - skipped"
 msgstr "%s: atlandı: %s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "\"%s\"e yazıyor\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "anahtar %s: anahtar malzemesi kartta - atlandı\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "gizli anahtarların ihracına izin verilmez\n"
 
@@ -1804,10 +1813,6 @@ msgstr "gizli anahtarların ihracına izin verilmez\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "anahtar %s: PGP 2.x tarzı bir anahtar - atlandı\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "anahtar %s: anahtar malzemesi kartta - atlandı\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "UYARI: hiçbir şey dışarı aktarılmadı\n"
 
@@ -1927,6 +1932,11 @@ msgstr "yeni bir anahtar çifti üretir"
 msgid "quickly add a new user-id"
 msgstr "yeni bir anahtar çifti üretir"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "yeni bir anahtar çifti üretir"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2282,6 +2292,11 @@ msgstr "%s:%d: geçersiz içselleştirme seçenekleri\n"
 msgid "invalid import options\n"
 msgstr "içselleştirme seçenekleri geçersiz\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "liste seçenekleri geçersiz\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d geçersiz dışsallaştırma seçenekleri\n"
@@ -2616,6 +2631,11 @@ msgstr "ithalat sonrası güvence veritabanını güncellemez"
 msgid "do not update the trustdb after import"
 msgstr "ithalat sonrası güvence veritabanını güncellemez"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "parmakizini gösterir"
+
 msgid "only accept updates to existing keys"
 msgstr "güncellemeleri sadece mevcut anahtarlar için kabul eder"
 
@@ -2625,6 +2645,9 @@ msgstr "ithalat sonrası anahtardan kullanışsız parçaları kaldırır"
 msgid "remove as much as possible from key after import"
 msgstr "ithalat sonrası anahtardan mümkün olduğunca çok şey kaldırır"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "%d türündeki blok atlanıyor\n"
@@ -2773,11 +2796,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "yazılabilir bir anahtar zinciri yok: %s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "\"%s\"e yazıyor\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "\"%s\" anahtarlığına yazarken hata oluştu: %s\n"
@@ -3566,6 +3584,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Güncelleme gereği olmadığından anahtar değişmedi.\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "Anahtar üretimi başarısızlığa uğradı: %s\n"
+
+#, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "parmakizi geçersiz"
@@ -3905,6 +3928,10 @@ msgid "no secret key\n"
 msgstr "gizli anahtar yok\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "kullanıcı kimliği \"%s\" zaten iptal edilmişti\n"
 
@@ -4438,10 +4465,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "Anahtar zinciri"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "\"%s\" atlandı: %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Birincil anahtar parmak izi:"
 
@@ -4562,6 +4585,10 @@ msgid "no keyserver known\n"
 msgstr "bir anahtar sunucusu eylemi yok!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "\"%s\" atlandı: %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "%s anahtarı %s adresine gönderiliyor\n"
 
index 0a1fdef..97442c8 100644 (file)
--- a/po/uk.po
+++ b/po/uk.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: GNU gnupg 2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2016-05-10 18:21+0300\n"
+"PO-Revision-Date: 2016-07-10 15:11+0300\n"
 "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
 "Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
 "Language: uk\n"
@@ -322,7 +322,7 @@ msgid "csh-style command output"
 msgstr "виведення команд у форматі csh"
 
 msgid "|FILE|read options from FILE"
-msgstr "прочитати параметри з вказаного файла"
+msgstr "|FILE|прочитати параметри з вказаного файла"
 
 msgid "do not detach from the console"
 msgstr "не від’єднувати від консолі"
@@ -334,16 +334,16 @@ msgid "use a log file for the server"
 msgstr "використовувати файл журналу для сервера"
 
 msgid "|PGM|use PGM as the PIN-Entry program"
-msgstr "використовувати вказану програму пінзаписів"
+msgstr "|PGM|використовувати вказану програму пінзаписів"
 
 msgid "|PGM|use PGM as the SCdaemon program"
-msgstr "використовувати вказану програму SCdaemon"
+msgstr "|PGM|використовувати вказану програму SCdaemon"
 
 msgid "do not use the SCdaemon"
 msgstr "не використовувати SCdaemon"
 
 msgid "|NAME|accept some commands via NAME"
-msgstr "приймати певні команди через NAME"
+msgstr "|NAME|приймати певні команди через NAME"
 
 msgid "ignore requests to change the TTY"
 msgstr "ігнорувати запити щодо зміни TTY"
@@ -352,7 +352,7 @@ msgid "ignore requests to change the X display"
 msgstr "ігнорувати запити щодо зміни графічного дисплея"
 
 msgid "|N|expire cached PINs after N seconds"
-msgstr "вважати кешовані пінкоди за вказану кількість секунд"
+msgstr "|N|вважати кешовані пінкоди за вказану кількість секунд"
 
 msgid "do not use the PIN cache when signing"
 msgstr "не використовувати кеш пін-кодів для підписування"
@@ -1683,6 +1683,14 @@ msgstr "вилучити максимум частин з ключа під ча
 msgid " - skipped"
 msgstr " - пропущено"
 
+#, c-format
+msgid "writing to '%s'\n"
+msgstr "записуємо до «%s»\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "ключ %s: матеріал ключа на карті — пропущено\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "експортування закритих ключів заборонено\n"
 
@@ -1690,10 +1698,6 @@ msgstr "експортування закритих ключів заборон
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "ключ %s: ключ у стилі PGP 2.x — пропущено\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "ключ %s: матеріал ключа на карті — пропущено\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "УВАГА: нічого не експортовано\n"
 
@@ -1803,6 +1807,9 @@ msgstr "швидке створення пари ключів"
 msgid "quickly add a new user-id"
 msgstr "швидке додавання нового ідентифікатора користувача"
 
+msgid "quickly revoke a user-id"
+msgstr "швидке відкликання ідентифікатора користувача"
+
 msgid "full featured key pair generation"
 msgstr "повноцінне створення пари ключів"
 
@@ -2133,6 +2140,10 @@ msgid "invalid import options\n"
 msgstr "некоректні параметри імпортування\n"
 
 #, c-format
+msgid "invalid filter option: %s\n"
+msgstr "некоректний параметр фільтрування: %s\n"
+
+#, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: некоректні параметри експортування\n"
 
@@ -2426,16 +2437,16 @@ msgid "the given preferred keyserver URL is invalid\n"
 msgstr "вказана адреса основного сервера ключів є некоректною\n"
 
 msgid "|FILE|take the keys from the keyring FILE"
-msgstr "визначити ключі з файла сховища ключів ФАЙЛ"
+msgstr "|FILE|визначити ключі з файла сховища ключів ФАЙЛ"
 
 msgid "make timestamp conflicts only a warning"
 msgstr "супроводжувати конфлікти часових позначок лише попередженнями"
 
 msgid "|FD|write status info to this FD"
-msgstr "записувати до дескриптора файла дані щодо стану"
+msgstr "|FD|записувати до дескриптора файла дані щодо стану"
 
 msgid "|ALGO|reject signatures made with ALGO"
-msgstr ""
+msgstr "|ALGO|відкидати підписи, створені за допомогою алгоритму ALGO"
 
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Використання: gpgv [параметри] [файли] (-h — довідка)"
@@ -2466,6 +2477,9 @@ msgstr "не вилучати значень власної довіри під
 msgid "do not update the trustdb after import"
 msgstr "не оновлювати базу даних довіри після імпортування"
 
+msgid "show key during import"
+msgstr "показувати ключ під час імпортування"
+
 msgid "only accept updates to existing keys"
 msgstr "приймати оновлення лише вже створених ключів"
 
@@ -2475,6 +2489,9 @@ msgstr "вилучити невикористані частини ключа п
 msgid "remove as much as possible from key after import"
 msgstr "вилучити максимум частин з ключа після імпортування"
 
+msgid "run import filters and export key immediately"
+msgstr "запустити фільтри імпортування та експортувати ключ негайно"
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "пропускаємо блок типу %d\n"
@@ -2619,10 +2636,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "не виявлено придатного до запису сховища ключів: %s\n"
 
 #, c-format
-msgid "writing to '%s'\n"
-msgstr "записуємо до «%s»\n"
-
-#, c-format
 msgid "error writing keyring '%s': %s\n"
 msgstr "помилка під час спроби запису сховища ключів «%s»: %s\n"
 
@@ -3368,6 +3381,10 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Ключ не змінено, отже оновлення непотрібне.\n"
 
 #, c-format
+msgid "User ID revocation failed: %s\n"
+msgstr "Спроба відкликання ідентифікатор користувача зазнала невдачі: %s\n"
+
+#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "«%s» не є відбитком\n"
 
@@ -3682,6 +3699,10 @@ msgid "no secret key\n"
 msgstr "немає закритого ключа\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr "спроба відкликати ідентифікатор, який не належить користувачеві: %s\n"
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "ідентифікатор користувача «%s» вже відкликано\n"
 
@@ -4197,10 +4218,6 @@ msgstr[2] ""
 msgid "Keyring"
 msgstr "Сховище ключів"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "пропущено «%s»: %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "Основний відбиток ключа:"
 
@@ -4320,6 +4337,10 @@ msgid "no keyserver known\n"
 msgstr "немає відомих серверів ключів\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "пропущено «%s»: %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "надсилаємо ключ %s на %s\n"
 
@@ -5914,10 +5935,8 @@ msgstr "[невідома]"
 msgid "[  undef ]"
 msgstr "[не визн.]"
 
-#, fuzzy
-#| msgid "never"
 msgid "[  never ]"
-msgstr "ніколи"
+msgstr "[ ніколи ]"
 
 msgid "[marginal]"
 msgstr "[неповна ]"
@@ -6766,7 +6785,7 @@ msgid "|N|number of certificates to include"
 msgstr "кількість сертифікатів, які слід включити"
 
 msgid "|FILE|take policy information from FILE"
-msgstr "взяти дані щодо правил з вказаного файла"
+msgstr "|FILE|взяти дані щодо правил з вказаного файла"
 
 msgid "do not check certificate policies"
 msgstr "не перевіряти правила сертифікатів"
@@ -6778,10 +6797,10 @@ msgid "don't use the terminal at all"
 msgstr "взагалі не використовувати термінал"
 
 msgid "|FILE|write a server mode log to FILE"
-msgstr "записувати журнал режиму сервера до файла"
+msgstr "|FILE|записувати журнал режиму сервера до файла"
 
 msgid "|FILE|write an audit log to FILE"
-msgstr "записувати журнал перевірки до файла"
+msgstr "|FILE|записувати журнал перевірки до файла"
 
 msgid "batch mode: never ask"
 msgstr "пакетний режим: нічого не запитувати"
@@ -6793,7 +6812,7 @@ msgid "assume no on most questions"
 msgstr "вважати відповіддю на більшість питань «ні»"
 
 msgid "|FILE|add keyring to the list of keyrings"
-msgstr "додати сховище ключів до списку сховищ ключів"
+msgstr "|FILE|додати сховище ключів до списку сховищ ключів"
 
 msgid "|USER-ID|use USER-ID as default secret key"
 msgstr ""
@@ -7680,7 +7699,7 @@ msgid "|N|do not return more than N items in one query"
 msgstr "|N|повертати не більше за вказану кількість записів на запит"
 
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
-msgstr "|ФАЙЛ|використовувати сертифікати CA з файла ФАЙЛ для HKP крізь TLS"
+msgstr "|FILE|використовувати сертифікати CA з файла для HKP крізь TLS"
 
 msgid "route all network traffic via Tor"
 msgstr "маршрутизувати увесь обмін даними з мережею через Tor"
index 034ee5c..41613c7 100644 (file)
@@ -1757,6 +1757,15 @@ msgstr "导出时尽可能清除密钥中的可选部分"
 msgid " - skipped"
 msgstr "%s:已跳过:%s\n"
 
+#, fuzzy, c-format
+#| msgid "writing to `%s'\n"
+msgid "writing to '%s'\n"
+msgstr "正在写入‘%s’\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "密钥 %s:密钥在卡上——已跳过\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "不允许导出私钥\n"
 
@@ -1764,10 +1773,6 @@ msgstr "不允许导出私钥\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "密钥 %s:PGP 2.x 样式的密钥――已跳过\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "密钥 %s:密钥在卡上——已跳过\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "警告:没有导出任何东西\n"
 
@@ -1886,6 +1891,11 @@ msgstr "生成一副新的密钥对"
 msgid "quickly add a new user-id"
 msgstr "生成一副新的密钥对"
 
+#, fuzzy
+#| msgid "generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "生成一副新的密钥对"
+
 msgid "full featured key pair generation"
 msgstr ""
 
@@ -2237,6 +2247,11 @@ msgstr "%s:%d:无效的导入选项\n"
 msgid "invalid import options\n"
 msgstr "无效的导入选项\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "无效的列表选项\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d:无效的导出选项\n"
@@ -2567,6 +2582,11 @@ msgstr "导入后不更新信任度数据库"
 msgid "do not update the trustdb after import"
 msgstr "导入后不更新信任度数据库"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "显示密钥指纹"
+
 msgid "only accept updates to existing keys"
 msgstr "只接受对已有密钥的更新"
 
@@ -2576,6 +2596,9 @@ msgstr "导入后清除密钥中无用的部分"
 msgid "remove as much as possible from key after import"
 msgstr "导入后尽可能清除密钥中的可选部分"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "跳过 %d 样式的区块\n"
@@ -2717,11 +2740,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "找不到可写的钥匙环:%s\n"
 
 #, fuzzy, c-format
-#| msgid "writing to `%s'\n"
-msgid "writing to '%s'\n"
-msgstr "正在写入‘%s’\n"
-
-#, fuzzy, c-format
 #| msgid "error writing keyring `%s': %s\n"
 msgid "error writing keyring '%s': %s\n"
 msgstr "写入钥匙环‘%s’时出错: %s\n"
@@ -3459,6 +3477,11 @@ msgid "Key not changed so no update needed.\n"
 msgstr "密钥没有变动所以不需要更新。\n"
 
 #, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "生成密钥失败:%s\n"
+
+#, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "指纹无效"
@@ -3775,6 +3798,10 @@ msgid "no secret key\n"
 msgstr "没有私钥\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "用户标识“%s”已经被吊销。\n"
 
@@ -4289,10 +4316,6 @@ msgstr[1] ""
 msgid "Keyring"
 msgstr "钥匙环"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "“%s”已跳过:%s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "主钥指纹:"
 
@@ -4413,6 +4436,10 @@ msgid "no keyserver known\n"
 msgstr "公钥服务器无动作!\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "“%s”已跳过:%s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "将密钥‘%s’上传到 %s\n"
 
index 984ef55..d9a4bb8 100644 (file)
@@ -1666,6 +1666,14 @@ msgstr "匯出時盡可能地從金鑰中移除"
 msgid " - skipped"
 msgstr " - 已跳過"
 
+#, c-format
+msgid "writing to '%s'\n"
+msgstr "正在寫入 '%s'\n"
+
+#, c-format
+msgid "key %s: key material on-card - skipped\n"
+msgstr "金鑰 %s: 金鑰資料在卡片上 - 已跳過\n"
+
 msgid "exporting secret keys not allowed\n"
 msgstr "不允許匯出私鑰\n"
 
@@ -1673,10 +1681,6 @@ msgstr "不允許匯出私鑰\n"
 msgid "key %s: PGP 2.x style key - skipped\n"
 msgstr "金鑰 %s: PGP 2.x 型態的金鑰 - 已跳過\n"
 
-#, c-format
-msgid "key %s: key material on-card - skipped\n"
-msgstr "金鑰 %s: 金鑰資料在卡片上 - 已跳過\n"
-
 msgid "WARNING: nothing exported\n"
 msgstr "警告: 沒有匯出任何東西\n"
 
@@ -1790,6 +1794,11 @@ msgstr "快速產生新的金鑰對"
 msgid "quickly add a new user-id"
 msgstr "快速產生新的金鑰對"
 
+#, fuzzy
+#| msgid "quickly generate a new key pair"
+msgid "quickly revoke a user-id"
+msgstr "快速產生新的金鑰對"
+
 msgid "full featured key pair generation"
 msgstr "全能金鑰對生成"
 
@@ -2103,6 +2112,11 @@ msgstr "%s:%d: 無效的匯入選項\n"
 msgid "invalid import options\n"
 msgstr "無效的匯入選項\n"
 
+#, fuzzy, c-format
+#| msgid "invalid list options\n"
+msgid "invalid filter option: %s\n"
+msgstr "無效的清單選項\n"
+
 #, c-format
 msgid "%s:%d: invalid export options\n"
 msgstr "%s:%d: 無效的匯出選項\n"
@@ -2422,6 +2436,11 @@ msgstr "匯入後不要更新信任資料庫"
 msgid "do not update the trustdb after import"
 msgstr "匯入後不要更新信任資料庫"
 
+#, fuzzy
+#| msgid "show key fingerprint"
+msgid "show key during import"
+msgstr "顯示金鑰指紋"
+
 msgid "only accept updates to existing keys"
 msgstr "祇接受既有金鑰的更新"
 
@@ -2431,6 +2450,9 @@ msgstr "匯入後從金鑰中移除無法使用的部分"
 msgid "remove as much as possible from key after import"
 msgstr "匯入後盡可能地從金鑰中移除"
 
+msgid "run import filters and export key immediately"
+msgstr ""
+
 #, c-format
 msgid "skipping block of type %d\n"
 msgstr "正在跳過 %d 型態的區塊\n"
@@ -2571,10 +2593,6 @@ msgid "no writable keyring found: %s\n"
 msgstr "找不到可寫入的鑰匙圈: %s\n"
 
 #, c-format
-msgid "writing to '%s'\n"
-msgstr "正在寫入 '%s'\n"
-
-#, c-format
 msgid "error writing keyring '%s': %s\n"
 msgstr "寫入鑰匙圈 '%s' 時出錯: %s\n"
 
@@ -3296,6 +3314,11 @@ msgstr "更新失敗: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "金鑰沒有變更所以不需要更新.\n"
 
+#, fuzzy, c-format
+#| msgid "Key generation failed: %s\n"
+msgid "User ID revocation failed: %s\n"
+msgstr "產生金鑰失敗: %s\n"
+
 #, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\" 不是指紋\n"
@@ -3607,6 +3630,10 @@ msgid "no secret key\n"
 msgstr "沒有私鑰\n"
 
 #, c-format
+msgid "tried to revoke a non-user ID: %s\n"
+msgstr ""
+
+#, c-format
 msgid "user ID \"%s\" is already revoked\n"
 msgstr "使用者 ID \"%s\" 已撤銷\n"
 
@@ -4099,10 +4126,6 @@ msgstr[0] "警告: %lu 把金鑰因尺寸太大已跳過\n"
 msgid "Keyring"
 msgstr "鑰匙圈"
 
-#, c-format
-msgid "skipped \"%s\": %s\n"
-msgstr "已跳過 \"%s\": %s\n"
-
 msgid "Primary key fingerprint:"
 msgstr "               主鑰指紋:"
 
@@ -4219,6 +4242,10 @@ msgid "no keyserver known\n"
 msgstr "無效的金鑰伺服器選項\n"
 
 #, c-format
+msgid "skipped \"%s\": %s\n"
+msgstr "已跳過 \"%s\": %s\n"
+
+#, c-format
 msgid "sending key %s to %s\n"
 msgstr "遞送金鑰 %s 至 %s\n"
 
index 985404f..7a093f6 100644 (file)
@@ -975,7 +975,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
       handle->max_ifsd = 48;
     }
 
-  if (handle->id_vendor == VENDOR_GEMPC && handle->id_product == GEMPC_CT30)
+  if (handle->id_vendor == VENDOR_GEMPC)
     {
       DEBUGOUT ("enabling product quirk: disable non-null NAD\n");
       handle->nonnull_nad = 0;
index 9c11cad..7dbb9c7 100644 (file)
@@ -156,6 +156,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
   ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen",
                 N_("use variable length input for pinpad")),
+  ARGPARSE_s_s (oHomedir,    "homedir",      "@"),
 
   ARGPARSE_end ()
 };
index 307d829..f349763 100644 (file)
@@ -25,7 +25,7 @@ else
 openpgp =
 endif
 
-SUBDIRS = ${openpgp} . pkits
+SUBDIRS = gpgscm ${openpgp} . migrations pkits
 
 GPGSM = ../sm/gpgsm
 
@@ -48,12 +48,12 @@ EXTRA_DIST = runtest inittests $(testscripts) ChangeLog-2011 \
              samplekeys/cert_g10code_test1.pem \
              samplekeys/cert_g10code_theo1.pem
 
-# We used to run $(testscripts) here but these asschk scripts ares not
-# completely reliable in all enviromnets and thus we better disable
-# them.  The tests are anyway way to minimal.  We will eventually
+# We used to run $(testscripts) here but these asschk scripts are not
+# completely reliable in all enviroments and thus we better disable
+# them.  The tests are anyway way too minimal.  We will eventually
 # write new tests based on gpg-connect-agent which has a full fledged
 # script language and thus makes it far easier to write tests than to
-# use the low--level asschk stuff.
+# use that low-level asschk stuff.
 TESTS =
 
 CLEANFILES = inittests.stamp x y y z out err \
diff --git a/tests/gpgscm/LICENSE.TinySCHEME b/tests/gpgscm/LICENSE.TinySCHEME
new file mode 100644 (file)
index 0000000..23a7e85
--- /dev/null
@@ -0,0 +1,31 @@
+                         LICENSE TERMS
+
+Copyright (c) 2000, Dimitrios Souflis
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+Neither the name of Dimitrios Souflis nor the names of the
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tests/gpgscm/Makefile.am b/tests/gpgscm/Makefile.am
new file mode 100644 (file)
index 0000000..e57a4bb
--- /dev/null
@@ -0,0 +1,59 @@
+# TinyScheme-based test driver.
+#
+# Copyright (C) 2016 g10 Code GmbH
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+EXTRA_DIST = \
+       LICENSE.TinySCHEME \
+       Manual.txt \
+       ffi.scm \
+       init.scm \
+       lib.scm \
+       repl.scm \
+       t-child.scm \
+       tests.scm
+
+AM_CPPFLAGS = -I$(top_srcdir)/common
+include $(top_srcdir)/am/cmacros.am
+
+AM_CFLAGS =
+
+CLEANFILES =
+
+bin_PROGRAMS = gpgscm
+noinst_PROGRAMS = t-child
+
+common_libs = ../$(libcommon)
+commonpth_libs = ../$(libcommonpth)
+
+gpgscm_CFLAGS = -imacros scheme-config.h \
+       $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
+gpgscm_SOURCES = main.c private.h ffi.c ffi.h ffi-private.h \
+       scheme-config.h opdefines.h scheme.c scheme.h scheme-private.h
+gpgscm_LDADD = $(LDADD) $(common_libs) \
+       $(NETLIBS) $(LIBICONV) $(LIBREADLINE) \
+       $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS)
+
+t_child_SOURCES = t-child.c
+
+# Make sure that all libs are build before we use them.  This is
+# important for things like make -j2.
+$(PROGRAMS): $(common_libs)
+
+check-local: gpgscm$(EXEEXT) t-child$(EXEEXT)
+       EXEEXT=$(EXEEXT) GPGSCM_PATH=$(srcdir) \
+               ./gpgscm$(EXEEXT) $(srcdir)/t-child.scm
diff --git a/tests/gpgscm/Manual.txt b/tests/gpgscm/Manual.txt
new file mode 100644 (file)
index 0000000..9fd294f
--- /dev/null
@@ -0,0 +1,444 @@
+
+
+                       TinySCHEME Version 1.41
+
+                    "Safe if used as prescribed"
+                    -- Philip K. Dick, "Ubik"
+
+This software is open source, covered by a BSD-style license.
+Please read accompanying file COPYING.
+-------------------------------------------------------------------------------
+
+     This Scheme interpreter is based on MiniSCHEME version 0.85k4
+     (see miniscm.tar.gz in the Scheme Repository)
+     Original credits in file MiniSCHEMETribute.txt.
+
+     D. Souflis (dsouflis@acm.org)
+
+-------------------------------------------------------------------------------
+     What is TinyScheme?
+     -------------------
+
+     TinyScheme is a lightweight Scheme interpreter that implements as large
+     a subset of R5RS as was possible without getting very large and
+     complicated. It is meant to be used as an embedded scripting interpreter
+     for other programs. As such, it does not offer IDEs or extensive toolkits
+     although it does sport a small top-level loop, included conditionally.
+     A lot of functionality in TinyScheme is included conditionally, to allow
+     developers freedom in balancing features and footprint.
+
+     As an embedded interpreter, it allows multiple interpreter states to
+     coexist in the same program, without any interference between them.
+     Programmatically, foreign functions in C can be added and values
+     can be defined in the Scheme environment. Being a quite small program,
+     it is easy to comprehend, get to grips with, and use.
+
+     Known bugs
+     ----------
+
+     TinyScheme is known to misbehave when memory is exhausted.
+
+
+     Things that keep missing, or that need fixing
+     ---------------------------------------------
+
+     There are no hygienic macros. No rational or
+     complex numbers. No unwind-protect and call-with-values.
+
+     Maybe (a subset of) SLIB will work with TinySCHEME...
+
+     Decent debugging facilities are missing. Only tracing is supported
+     natively.
+
+
+     Scheme Reference
+     ----------------
+
+     If something seems to be missing, please refer to the code and
+     "init.scm", since some are library functions.  Refer to the MiniSCHEME
+     readme as a last resort.
+
+          Environments
+     (interaction-environment)
+     See R5RS. In TinySCHEME, immutable list of association lists.
+
+     (current-environment)
+     The environment in effect at the time of the call. An example of its
+     use and its utility can be found in the sample code that implements
+     packages in "init.scm":
+
+          (macro (package form)
+               `(apply (lambda ()
+                         ,@(cdr form)
+                         (current-environment))))
+
+     The environment containing the (local) definitions inside the closure
+     is returned as an immutable value.
+
+     (defined? <symbol>) (defined? <symbol> <environment>)
+     Checks whether the given symbol is defined in the current (or given)
+     environment.
+
+          Symbols
+     (gensym)
+     Returns a new interned symbol each time. Will probably move to the
+     library when string->symbol is implemented.
+
+          Directives
+     (gc)
+     Performs garbage collection immediatelly.
+
+     (gc-verbose) (gc-verbose <bool>)
+     The argument (defaulting to #t) controls whether GC produces
+     visible outcome.
+
+     (quit) (quit <num>)
+     Stops the interpreter and sets the 'retcode' internal field (defaults
+     to 0). When standalone, 'retcode' is returned as exit code to the OS.
+
+     (tracing <num>)
+     1, turns on tracing. 0 turns it off. (Only when USE_TRACING is 1).
+
+          Mathematical functions
+     Since rationals and complexes are absent, the respective functions
+     are also missing.
+     Supported: exp, log, sin, cos, tan, asin, acos, atan, floor, ceiling,
+     trunc, round and also sqrt and expt when USE_MATH=1.
+     Number-theoretical quotient, remainder and modulo, gcd, lcm.
+     Library: exact?, inexact?, odd?, even?, zero?, positive?, negative?,
+     exact->inexact. inexact->exact is a core function.
+
+          Type predicates
+     boolean?,eof-object?,symbol?,number?,string?,integer?,real?,list?,null?,
+     char?,port?,input-port?,output-port?,procedure?,pair?,environment?',
+     vector?. Also closure?, macro?.
+
+          Types
+     Types supported:
+
+          Numbers (integers and reals)
+          Symbols
+          Pairs
+          Strings
+          Characters
+          Ports
+          Eof object
+          Environments
+          Vectors
+
+          Literals
+     String literals can contain escaped quotes \" as usual, but also
+     \n, \r, \t, \xDD (hex representations) and \DDD (octal representations).
+     Note also that it is possible to include literal newlines in string
+     literals, e.g.
+
+          (define s "String with newline here
+          and here
+          that can function like a HERE-string")
+
+     Character literals contain #\space and #\newline and are supplemented
+     with #\return and #\tab, with obvious meanings. Hex character
+     representations are allowed (e.g. #\x20 is #\space).
+     When USE_ASCII_NAMES is defined, various control characters can be
+     referred to by their ASCII name.
+     0      #\nul             17       #\dc1
+     1      #\soh             18       #\dc2
+     2      #\stx             19       #\dc3
+     3      #\etx             20       #\dc4
+     4      #\eot             21       #\nak
+     5      #\enq             22       #\syn
+     6      #\ack             23       #\etv
+     7      #\bel             24       #\can
+     8      #\bs              25       #\em
+     9      #\ht              26       #\sub
+     10             #\lf              27       #\esc
+     11             #\vt              28       #\fs
+     12             #\ff              29       #\gs
+     13             #\cr              30       #\rs
+     14             #\so              31       #\us
+     15             #\si
+     16             #\dle             127      #\del
+
+     Numeric literals support #x #o #b and #d. Flonums are currently read only
+     in decimal notation. Full grammar will be supported soon.
+
+          Quote, quasiquote etc.
+     As usual.
+
+          Immutable values
+     Immutable pairs cannot be modified by set-car! and set-cdr!.
+     Immutable strings cannot be modified via string-set!
+
+          I/O
+     As per R5RS, plus String Ports (see below).
+     current-input-port, current-output-port,
+     close-input-port, close-output-port, input-port?, output-port?,
+     open-input-file, open-output-file.
+     read, write, display, newline, write-char, read-char, peek-char.
+     char-ready? returns #t only for string ports, because there is no
+     portable way in stdio to determine if a character is available.
+     Also open-input-output-file, set-input-port, set-output-port (not R5RS)
+     Library: call-with-input-file, call-with-output-file,
+     with-input-from-file, with-output-from-file and
+     with-input-output-from-to-files, close-port and input-output-port?
+     (not R5RS).
+     String Ports: open-input-string, open-output-string, get-output-string,
+     open-input-output-string. Strings can be used with I/O routines.
+
+          Vectors
+     make-vector, vector, vector-length, vector-ref, vector-set!, list->vector,
+     vector-fill!, vector->list, vector-equal? (auxiliary function, not R5RS)
+
+          Strings
+     string, make-string, list->string, string-length, string-ref, string-set!,
+     substring, string->list, string-fill!, string-append, string-copy.
+     string=?, string<?, string>?, string>?, string<=?, string>=?.
+     (No string-ci*? yet). string->number, number->string. Also atom->string,
+     string->atom (not R5RS).
+
+          Symbols
+     symbol->string, string->symbol
+
+          Characters
+     integer->char, char->integer.
+     char=?, char<?, char>?, char<=?, char>=?.
+     (No char-ci*?)
+
+          Pairs & Lists
+     cons, car, cdr, list, length, map, for-each, foldr, list-tail,
+     list-ref, last-pair, reverse, append.
+     Also member, memq, memv, based on generic-member, assoc, assq, assv
+     based on generic-assoc.
+
+          Streams
+     head, tail, cons-stream
+
+          Control features
+     Apart from procedure?, also macro? and closure?
+     map, for-each, force, delay, call-with-current-continuation (or call/cc),
+     eval, apply. 'Forcing' a value that is not a promise produces the value.
+     There is no call-with-values, values, nor dynamic-wind. Dynamic-wind in
+     the presence of continuations would require support from the abstract
+     machine itself.
+
+          Property lists
+     TinyScheme inherited from MiniScheme property lists for symbols.
+     put, get.
+
+          Dynamically-loaded extensions
+     (load-extension <filename without extension>)
+     Loads a DLL declaring foreign procedures. On Unix/Linux, one can make use
+     of the ld.so.conf file or the LD_RUN_PATH system variable in order to place
+     the library in a directory other than the current one. Please refer to the
+     appropriate 'man' page.
+
+          Esoteric procedures
+     (oblist)
+     Returns the oblist, an immutable list of all the symbols.
+
+     (macro-expand <form>)
+     Returns the expanded form of the macro call denoted by the argument
+
+     (define-with-return (<procname> <args>...) <body>)
+     Like plain 'define', but makes the continuation available as 'return'
+     inside the procedure. Handy for imperative programs.
+
+     (new-segment <num>)
+     Allocates more memory segments.
+
+     defined?
+     See "Environments"
+
+     (get-closure-code <closure>)
+     Gets the code as scheme data.
+
+     (make-closure <code> <environment>)
+     Makes a new closure in the given environment.
+
+          Obsolete procedures
+     (print-width <object>)
+
+     Programmer's Reference
+     ----------------------
+
+     The interpreter state is initialized with "scheme_init".
+     Custom memory allocation routines can be installed with an alternate
+     initialization function: "scheme_init_custom_alloc".
+     Files can be loaded with "scheme_load_file". Strings containing Scheme
+     code can be loaded with "scheme_load_string". It is a good idea to
+     "scheme_load" init.scm before anything else.
+
+     External data for keeping external state (of use to foreign functions)
+     can be installed with "scheme_set_external_data".
+     Foreign functions are installed with "assign_foreign". Additional
+     definitions can be added to the interpreter state, with "scheme_define"
+     (this is the way HTTP header data and HTML form data are passed to the
+     Scheme script in the Altera SQL Server). If you wish to define the
+     foreign function in a specific environment (to enhance modularity),
+     use "assign_foreign_env".
+
+     The procedure "scheme_apply0" has been added with persistent scripts in
+     mind. Persistent scripts are loaded once, and every time they are needed
+     to produce HTTP output, appropriate data are passed through global
+     definitions and function "main" is called to do the job. One could
+     add easily "scheme_apply1" etc.
+
+     The interpreter state should be deinitialized with "scheme_deinit".
+
+     DLLs containing foreign functions should define a function named
+     init_<base-name>. E.g. foo.dll should define init_foo, and bar.so
+     should define init_bar. This function should assign_foreign any foreign
+     function contained in the DLL.
+
+     The first dynamically loaded extension available for TinyScheme is
+     a regular expression library. Although it's by no means an
+     established standard, this library is supposed to be installed in
+     a directory mirroring its name under the TinyScheme location.
+
+
+     Foreign Functions
+     -----------------
+
+     The user can add foreign functions in C. For example, a function
+     that squares its argument:
+
+          pointer square(scheme *sc, pointer args) {
+           if(args!=sc->NIL) {
+               if(sc->isnumber(sc->pair_car(args))) {
+                    double v=sc->rvalue(sc->pair_car(args));
+                    return sc->mk_real(sc,v*v);
+               }
+           }
+           return sc->NIL;
+          }
+
+   Foreign functions are now defined as closures:
+
+   sc->interface->scheme_define(
+        sc,
+        sc->global_env,
+        sc->interface->mk_symbol(sc,"square"),
+        sc->interface->mk_foreign_func(sc, square));
+
+
+     Foreign functions can use the external data in the "scheme" struct
+     to implement any kind of external state.
+
+     External data are set with the following function:
+          void scheme_set_external_data(scheme *sc, void *p);
+
+     As of v.1.17, the canonical way for a foreign function in a DLL to
+     manipulate Scheme data is using the function pointers in sc->interface.
+
+     Standalone
+     ----------
+
+     Usage: tinyscheme -?
+     or:    tinyscheme [<file1> <file2> ...]
+     followed by
+              -1 <file> [<arg1> <arg2> ...]
+              -c <Scheme commands> [<arg1> <arg2> ...]
+     assuming that the executable is named tinyscheme.
+
+     Use - in the place of a filename to denote stdin.
+     The -1 flag is meant for #! usage in shell scripts. If you specify
+          #! /somewhere/tinyscheme -1
+     then tinyscheme will be called to process the file. For example, the
+     following script echoes the Scheme list of its arguments.
+
+              #! /somewhere/tinyscheme -1
+              (display *args*)
+
+     The -c flag permits execution of arbitrary Scheme code.
+
+
+     Error Handling
+     --------------
+
+     Errors are recovered from without damage. The user can install his
+     own handler for system errors, by defining *error-hook*. Defining
+     to '() gives the default behavior, which is equivalent to "error".
+     USE_ERROR_HOOK must be defined.
+
+     A simple exception handling mechanism can be found in "init.scm".
+     A new syntactic form is introduced:
+
+          (catch <expr returned exceptionally>
+               <expr1> <expr2> ... <exprN>)
+
+     "Catch" establishes a scope spanning multiple call-frames
+     until another "catch" is encountered.
+
+     Exceptions are thrown with:
+
+          (throw "message")
+
+     If used outside a (catch ...), reverts to (error "message").
+
+     Example of use:
+
+          (define (foo x) (write x) (newline) (/ x 0))
+
+          (catch (begin (display "Error!\n") 0)
+               (write "Before foo ... ")
+               (foo 5)
+               (write "After foo"))
+
+     The exception mechanism can be used even by system errors, by
+
+          (define *error-hook* throw)
+
+     which makes use of the error hook described above.
+
+     If necessary, the user can devise his own exception mechanism with
+     tagged exceptions etc.
+
+
+     Reader extensions
+     -----------------
+
+     When encountering an unknown character after '#', the user-specified
+     procedure *sharp-hook* (if any), is called to read the expression.
+     This can be used to extend the reader to handle user-defined constants
+     or whatever. It should be a procedure without arguments, reading from
+     the current input port (which will be the load-port).
+
+
+     Colon Qualifiers - Packages
+     ---------------------------
+
+     When USE_COLON_HOOK=1:
+     The lexer now recognizes the construction <qualifier>::<symbol> and
+     transforms it in the following manner (T is the transformation function):
+
+          T(<qualifier>::<symbol>) = (*colon-hook* 'T(<symbol>) <qualifier>)
+
+     where <qualifier> is a symbol not containing any double-colons.
+
+     As the definition is recursive, qualifiers can be nested.
+     The user can define his own *colon-hook*, to handle qualified names.
+     By default, "init.scm" defines *colon-hook* as EVAL. Consequently,
+     the qualifier must denote a Scheme environment, such as one returned
+     by (interaction-environment). "Init.scm" defines a new syntantic form,
+     PACKAGE, as a simple example. It is used like this:
+
+          (define toto
+               (package
+                    (define foo 1)
+                    (define bar +)))
+
+          foo                                     ==>  Error, "foo" undefined
+          (eval 'foo)                             ==>  Error, "foo" undefined
+          (eval 'foo toto)                        ==>  1
+          toto::foo                               ==>  1
+          ((eval 'bar toto) 2 (eval 'foo toto))   ==>  3
+          (toto::bar 2 toto::foo)                 ==>  3
+          (eval (bar 2 foo) toto)                 ==>  3
+
+     If the user installs another package infrastructure, he must define
+     a new 'package' procedure or macro to retain compatibility with supplied
+     code.
+
+     Note: Older versions used ':' as a qualifier. Unfortunately, the use
+     of ':' as a pseudo-qualifier in existing code (i.e. SLIB) essentially
+     precludes its use as a real qualifier.
diff --git a/tests/gpgscm/ffi-private.h b/tests/gpgscm/ffi-private.h
new file mode 100644 (file)
index 0000000..87f491f
--- /dev/null
@@ -0,0 +1,148 @@
+/* FFI interface for TinySCHEME.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GPGSCM_FFI_PRIVATE_H
+#define GPGSCM_FFI_PRIVATE_H
+
+#include <gpg-error.h>
+#include "scheme.h"
+#include "scheme-private.h"
+
+#define FFI_PROLOG()                                           \
+  unsigned int ffi_arg_index GPGRT_ATTR_UNUSED = 1;            \
+  int err GPGRT_ATTR_UNUSED = 0                                        \
+
+int ffi_bool_value (scheme *sc, pointer p);
+
+#define CONVERSION_number(SC, X) (SC)->vptr->ivalue (X)
+#define CONVERSION_string(SC, X) (SC)->vptr->string_value (X)
+#define CONVERSION_character(SC, X) (SC)->vptr->charvalue (X)
+#define CONVERSION_list(SC, X) (X)
+#define CONVERSION_bool(SC, X) ffi_bool_value ((SC), (X))
+#define CONVERSION_path(SC, X) (((SC)->vptr->is_string (X)       \
+                                 ? (SC)->vptr->string_value      \
+                                 : (SC)->vptr->symname) (X))
+
+#define IS_A_number(SC, X)     (SC)->vptr->is_number (X)
+#define IS_A_string(SC, X)     (SC)->vptr->is_string (X)
+#define IS_A_character(SC, X)  (SC)->vptr->is_character (X)
+#define IS_A_list(SC, X)       (SC)->vptr->is_list ((SC), X)
+#define IS_A_bool(SC, X)       ((X) == (SC)->F || (X) == (SC)->T)
+#define IS_A_path(SC, X)       ((SC)->vptr->is_string (X)      \
+                                || (SC)->vptr->is_symbol (X))
+
+#define FFI_ARG_OR_RETURN(SC, CTYPE, TARGET, WANT, ARGS)               \
+  do {                                                                 \
+  if ((ARGS) == (SC)->NIL)                                             \
+    return (SC)->vptr->mk_string ((SC),                                        \
+                                 "too few arguments: want "            \
+                                 #TARGET "("#WANT"/"#CTYPE")\n");      \
+  if (! IS_A_##WANT ((SC), pair_car (ARGS))) {                         \
+    char ffi_error_message[256];                                       \
+    snprintf (ffi_error_message, sizeof ffi_error_message,             \
+             "argument %d must be: " #WANT "\n", ffi_arg_index);       \
+    return  (SC)->vptr->mk_string ((SC), ffi_error_message);           \
+  }                                                                    \
+  TARGET = CONVERSION_##WANT (SC, pair_car (ARGS));                    \
+  ARGS = pair_cdr (ARGS);                                              \
+  ffi_arg_index += 1;                                                  \
+  } while (0)
+
+#define FFI_ARGS_DONE_OR_RETURN(SC, ARGS)                               \
+  do {                                                                 \
+  if ((ARGS) != (SC)->NIL)                                             \
+    return (SC)->vptr->mk_string ((SC), "too many arguments");         \
+  } while (0)
+
+#define FFI_RETURN_ERR(SC, ERR)                                        \
+  return _cons ((SC), mk_integer ((SC), (ERR)), (SC)->NIL, 1)
+
+#define FFI_RETURN(SC) FFI_RETURN_ERR (SC, err)
+
+#define FFI_RETURN_POINTER(SC, X)                                      \
+  return _cons ((SC), mk_integer ((SC), err),                          \
+               _cons ((SC), (X), (SC)->NIL, 1), 1)
+#define FFI_RETURN_INT(SC, X)                                          \
+  FFI_RETURN_POINTER ((SC), mk_integer ((SC), (X)))
+#define FFI_RETURN_STRING(SC, X)                       \
+  FFI_RETURN_POINTER ((SC), mk_string ((SC), (X)))
+
+char *ffi_schemify_name (const char *s, int macro);
+
+void ffi_scheme_eval (scheme *sc, const char *format, ...)
+  GPGRT_ATTR_PRINTF (2, 3);
+pointer ffi_sprintf (scheme *sc, const char *format, ...)
+  GPGRT_ATTR_PRINTF (2, 3);
+
+#define ffi_define_function_name(SC, NAME, F)                          \
+  do {                                                                 \
+    char *_fname = ffi_schemify_name ("_" #F, 0);                        \
+    scheme_define ((SC),                                               \
+                  (SC)->global_env,                                    \
+                  mk_symbol ((SC), _fname),                            \
+                  mk_foreign_func ((SC), (do_##F)));                   \
+    ffi_scheme_eval ((SC),                                             \
+                    "(define (%s . a) (ffi-apply \"%s\" %s a))",       \
+                    (NAME), (NAME), _fname);                           \
+    free (_fname);                                                      \
+  } while (0)
+
+#define ffi_define_function(SC, F)                                      \
+  do {                                                                 \
+    char *_name = ffi_schemify_name (#F, 0);                            \
+    ffi_define_function_name ((SC), _name, F);                          \
+    free (_name);                                                       \
+  } while (0)
+
+#define ffi_define_constant(SC, C)                                     \
+  do {                                                                 \
+    char *_name = ffi_schemify_name (#C, 1);                            \
+    scheme_define ((SC),                                                \
+                   (SC)->global_env,                                   \
+                   mk_symbol ((SC), _name),                             \
+                   mk_integer ((SC), (C)));                             \
+    free (_name);                                                       \
+  } while (0)
+
+#define ffi_define(SC, SYM, EXP)                                       \
+  scheme_define ((SC), (SC)->global_env, mk_symbol ((SC), (SYM)), EXP)
+
+#define ffi_define_variable_pointer(SC, C, P)                          \
+  do {                                                                 \
+    char *_name = ffi_schemify_name (#C, 0);                            \
+    scheme_define ((SC),                                                \
+                   (SC)->global_env,                                   \
+                   mk_symbol ((SC), _name),                             \
+                   (P));                                                \
+    free (_name);                                                       \
+  } while (0)
+
+#define ffi_define_variable_integer(SC, C)                             \
+  ffi_define_variable_pointer ((SC), C, (SC)->vptr->mk_integer ((SC), C))
+
+#define ffi_define_variable_string(SC, C)                              \
+  ffi_define_variable_pointer ((SC), C, (SC)->vptr->mk_string ((SC), C ?: ""))
+
+gpg_error_t ffi_list2argv (scheme *sc, pointer list,
+                          char ***argv, size_t *len);
+gpg_error_t ffi_list2intv (scheme *sc, pointer list,
+                          int **intv, size_t *len);
+
+#endif /* GPGSCM_FFI_PRIVATE_H */
diff --git a/tests/gpgscm/ffi.c b/tests/gpgscm/ffi.c
new file mode 100644 (file)
index 0000000..5494c4d
--- /dev/null
@@ -0,0 +1,1287 @@
+/* FFI interface for TinySCHEME.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <gpg-error.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#if HAVE_LIBREADLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#include "../../common/util.h"
+#include "../../common/exechelp.h"
+#include "../../common/sysutils.h"
+
+#include "private.h"
+#include "ffi.h"
+#include "ffi-private.h"
+
+\f
+
+int
+ffi_bool_value (scheme *sc, pointer p)
+{
+  return ! (p == sc->F);
+}
+
+
+\f
+static pointer
+do_logand (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  unsigned int v, acc = ~0;
+  while (args != sc->NIL)
+    {
+      FFI_ARG_OR_RETURN (sc, unsigned int, v, number, args);
+      acc &= v;
+    }
+  FFI_RETURN_INT (sc, acc);
+}
+
+static pointer
+do_logior (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  unsigned int v, acc = 0;
+  while (args != sc->NIL)
+    {
+      FFI_ARG_OR_RETURN (sc, unsigned int, v, number, args);
+      acc |= v;
+    }
+  FFI_RETURN_INT (sc, acc);
+}
+
+static pointer
+do_logxor (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  unsigned int v, acc = 0;
+  while (args != sc->NIL)
+    {
+      FFI_ARG_OR_RETURN (sc, unsigned int, v, number, args);
+      acc ^= v;
+    }
+  FFI_RETURN_INT (sc, acc);
+}
+
+static pointer
+do_lognot (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  unsigned int v;
+  FFI_ARG_OR_RETURN (sc, unsigned int, v, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  FFI_RETURN_INT (sc, ~v);
+}
+\f
+/* User interface.  */
+
+static pointer
+do_flush_stdio (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  fflush (stdout);
+  fflush (stderr);
+  FFI_RETURN (sc);
+}
+
+
+int use_libreadline;
+
+/* Read a string, and return a pointer to it.  Returns NULL on EOF. */
+char *
+rl_gets (const char *prompt)
+{
+  static char *line = NULL;
+  char *p;
+  xfree (line);
+
+#if HAVE_LIBREADLINE
+    {
+      line = readline (prompt);
+      if (line && *line)
+        add_history (line);
+    }
+#else
+    {
+      size_t max_size = 0xff;
+      printf ("%s", prompt);
+      fflush (stdout);
+      line = xtrymalloc (max_size);
+      if (line != NULL)
+        fgets (line, max_size, stdin);
+    }
+#endif
+
+  /* Strip trailing whitespace.  */
+  if (line && strlen (line) > 0)
+    for (p = &line[strlen (line) - 1]; isspace (*p); p--)
+      *p = 0;
+
+  return line;
+}
+
+static pointer
+do_prompt (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  const char *prompt;
+  const char *line;
+  FFI_ARG_OR_RETURN (sc, const char *, prompt, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  line = rl_gets (prompt);
+  if (! line)
+    FFI_RETURN_POINTER (sc, sc->EOF_OBJ);
+
+  FFI_RETURN_STRING (sc, line);
+}
+\f
+static pointer
+do_sleep (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  unsigned int seconds;
+  FFI_ARG_OR_RETURN (sc, unsigned int, seconds, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  sleep (seconds);
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_usleep (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  useconds_t microseconds;
+  FFI_ARG_OR_RETURN (sc, useconds_t, microseconds, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  usleep (microseconds);
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_chdir (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *name;
+  FFI_ARG_OR_RETURN (sc, char *, name, path, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  if (chdir (name))
+    FFI_RETURN_ERR (sc, errno);
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_strerror (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int error;
+  FFI_ARG_OR_RETURN (sc, int, error, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  FFI_RETURN_STRING (sc, gpg_strerror (error));
+}
+
+static pointer
+do_getenv (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *name;
+  char *value;
+  FFI_ARG_OR_RETURN (sc, char *, name, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  value = getenv (name);
+  FFI_RETURN_STRING (sc, value ? value : "");
+}
+
+static pointer
+do_setenv (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *name;
+  char *value;
+  int overwrite;
+  FFI_ARG_OR_RETURN (sc, char *, name, string, args);
+  FFI_ARG_OR_RETURN (sc, char *, value, string, args);
+  FFI_ARG_OR_RETURN (sc, int, overwrite, bool, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  FFI_RETURN_ERR (sc, gnupg_setenv (name, value, overwrite));
+}
+
+static pointer
+do_exit (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int retcode;
+  FFI_ARG_OR_RETURN (sc, int, retcode, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  exit (retcode);
+}
+
+/* XXX: use gnupgs variant b/c mode as string */
+static pointer
+do_open (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int fd;
+  char *pathname;
+  int flags;
+  mode_t mode = 0;
+  FFI_ARG_OR_RETURN (sc, char *, pathname, path, args);
+  FFI_ARG_OR_RETURN (sc, int, flags, number, args);
+  if (args != sc->NIL)
+    FFI_ARG_OR_RETURN (sc, mode_t, mode, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  fd = open (pathname, flags, mode);
+  if (fd == -1)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+  FFI_RETURN_INT (sc, fd);
+}
+
+static pointer
+do_fdopen (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  FILE *stream;
+  int fd;
+  char *mode;
+  int kind;
+  FFI_ARG_OR_RETURN (sc, int, fd, number, args);
+  FFI_ARG_OR_RETURN (sc, char *, mode, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  stream = fdopen (fd, mode);
+  if (stream == NULL)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+
+  if (setvbuf (stream, NULL, _IONBF, 0) != 0)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+
+  kind = 0;
+  if (strchr (mode, 'r'))
+    kind |= port_input;
+  if (strchr (mode, 'w'))
+    kind |= port_output;
+
+  FFI_RETURN_POINTER (sc, sc->vptr->mk_port_from_file (sc, stream, kind));
+}
+
+static pointer
+do_close (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int fd;
+  FFI_ARG_OR_RETURN (sc, int, fd, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  FFI_RETURN_ERR (sc, close (fd) == 0 ? 0 : gpg_error_from_syserror ());
+}
+
+static pointer
+do_mkdtemp (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *template;
+  char buffer[128];
+  char *name;
+  FFI_ARG_OR_RETURN (sc, char *, template, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  if (strlen (template) > sizeof buffer - 1)
+    FFI_RETURN_ERR (sc, EINVAL);
+  strncpy (buffer, template, sizeof buffer);
+
+  name = gnupg_mkdtemp (buffer);
+  if (name == NULL)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+  FFI_RETURN_STRING (sc, name);
+}
+
+static pointer
+do_unlink (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *name;
+  FFI_ARG_OR_RETURN (sc, char *, name, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  if (unlink (name) == -1)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+  FFI_RETURN (sc);
+}
+
+static gpg_error_t
+unlink_recursively (const char *name)
+{
+  gpg_error_t err = 0;
+  struct stat st;
+
+  if (stat (name, &st) == -1)
+    return gpg_error_from_syserror ();
+
+  if (S_ISDIR (st.st_mode))
+    {
+      DIR *dir;
+      struct dirent *dent;
+
+      dir = opendir (name);
+      if (dir == NULL)
+        return gpg_error_from_syserror ();
+
+      while ((dent = readdir (dir)))
+        {
+          char *child;
+
+          if (strcmp (dent->d_name, ".") == 0
+              || strcmp (dent->d_name, "..") == 0)
+            continue;
+
+          child = xtryasprintf ("%s/%s", name, dent->d_name);
+          if (child == NULL)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+
+          err = unlink_recursively (child);
+          xfree (child);
+          if (err == gpg_error_from_errno (ENOENT))
+            err = 0;
+          if (err)
+            goto leave;
+        }
+
+    leave:
+      closedir (dir);
+      if (! err)
+        rmdir (name);
+      return err;
+    }
+  else
+    if (unlink (name) == -1)
+      return gpg_error_from_syserror ();
+  return 0;
+}
+
+static pointer
+do_unlink_recursively (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *name;
+  FFI_ARG_OR_RETURN (sc, char *, name, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  err = unlink_recursively (name);
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_rename (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *old;
+  char *new;
+  FFI_ARG_OR_RETURN (sc, char *, old, string, args);
+  FFI_ARG_OR_RETURN (sc, char *, new, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  if (rename (old, new) == -1)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_getcwd (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  pointer result;
+  char *cwd;
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  cwd = gnupg_getcwd ();
+  if (cwd == NULL)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+  result = sc->vptr->mk_string (sc, cwd);
+  xfree (cwd);
+  FFI_RETURN_POINTER (sc, result);
+}
+
+static pointer
+do_mkdir (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *name;
+  char *mode;
+  FFI_ARG_OR_RETURN (sc, char *, name, string, args);
+  FFI_ARG_OR_RETURN (sc, char *, mode, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  if (gnupg_mkdir (name, mode) == -1)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_rmdir (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *name;
+  FFI_ARG_OR_RETURN (sc, char *, name, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  if (rmdir (name) == -1)
+    FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+  FFI_RETURN (sc);
+}
+
+\f
+
+/* estream functions.  */
+
+struct es_object_box
+{
+  estream_t stream;
+  int closed;
+};
+
+static void
+es_object_finalize (scheme *sc, void *data)
+{
+  struct es_object_box *box = data;
+  (void) sc;
+
+  if (! box->closed)
+    es_fclose (box->stream);
+  xfree (box);
+}
+
+static void
+es_object_to_string (scheme *sc, char *out, size_t size, void *data)
+{
+  struct es_object_box *box = data;
+  (void) sc;
+
+  snprintf (out, size, "#estream %p", box->stream);
+}
+
+static struct foreign_object_vtable es_object_vtable =
+  {
+    es_object_finalize,
+    es_object_to_string,
+  };
+
+static pointer
+es_wrap (scheme *sc, estream_t stream)
+{
+  struct es_object_box *box = xmalloc (sizeof *box);
+  if (box == NULL)
+    return sc->NIL;
+
+  box->stream = stream;
+  box->closed = 0;
+  return sc->vptr->mk_foreign_object (sc, &es_object_vtable, box);
+}
+
+static struct es_object_box *
+es_unwrap (scheme *sc, pointer object)
+{
+  (void) sc;
+
+  if (! is_foreign_object (object))
+    return NULL;
+
+  if (sc->vptr->get_foreign_object_vtable (object) != &es_object_vtable)
+    return NULL;
+
+  return sc->vptr->get_foreign_object_data (object);
+}
+
+#define CONVERSION_estream(SC, X)      es_unwrap (SC, X)
+#define IS_A_estream(SC, X)            es_unwrap (SC, X)
+
+static pointer
+do_es_fclose (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  struct es_object_box *box;
+  FFI_ARG_OR_RETURN (sc, struct es_object_box *, box, estream, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  err = es_fclose (box->stream);
+  if (! err)
+    box->closed = 1;
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_es_read (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  struct es_object_box *box;
+  size_t bytes_to_read;
+
+  pointer result;
+  void *buffer;
+  size_t bytes_read;
+
+  FFI_ARG_OR_RETURN (sc, struct es_object_box *, box, estream, args);
+  FFI_ARG_OR_RETURN (sc, size_t, bytes_to_read, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  buffer = xtrymalloc (bytes_to_read);
+  if (buffer == NULL)
+    FFI_RETURN_ERR (sc, ENOMEM);
+
+  err = es_read (box->stream, buffer, bytes_to_read, &bytes_read);
+  if (err)
+    FFI_RETURN_ERR (sc, err);
+
+  result = sc->vptr->mk_counted_string (sc, buffer, bytes_read);
+  xfree (buffer);
+  FFI_RETURN_POINTER (sc, result);
+}
+
+static pointer
+do_es_feof (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  struct es_object_box *box;
+  FFI_ARG_OR_RETURN (sc, struct es_object_box *, box, estream, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  FFI_RETURN_POINTER (sc, es_feof (box->stream) ? sc->T : sc->F);
+}
+
+static pointer
+do_es_write (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  struct es_object_box *box;
+  const char *buffer;
+  size_t bytes_to_write, bytes_written;
+
+  FFI_ARG_OR_RETURN (sc, struct es_object_box *, box, estream, args);
+  /* XXX how to get the length of the string buffer?  scheme strings
+     may contain \0.  */
+  FFI_ARG_OR_RETURN (sc, const char *, buffer, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  bytes_to_write = strlen (buffer);
+  while (bytes_to_write > 0)
+    {
+      err = es_write (box->stream, buffer, bytes_to_write, &bytes_written);
+      if (err)
+        break;
+      bytes_to_write -= bytes_written;
+      buffer += bytes_written;
+    }
+
+  FFI_RETURN (sc);
+}
+
+\f
+
+/* Process handling.  */
+
+static pointer
+do_spawn_process (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  pointer arguments;
+  char **argv;
+  size_t len;
+  unsigned int flags;
+
+  estream_t infp;
+  estream_t outfp;
+  estream_t errfp;
+  pid_t pid;
+
+  FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args);
+  FFI_ARG_OR_RETURN (sc, unsigned int, flags, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  err = ffi_list2argv (sc, arguments, &argv, &len);
+  if (err == gpg_error (GPG_ERR_INV_VALUE))
+    return ffi_sprintf (sc, "%luth element of first argument is "
+                        "neither string nor symbol",
+                        (unsigned long) len);
+  if (err)
+    FFI_RETURN_ERR (sc, err);
+
+  if (verbose > 1)
+    {
+      char **p;
+      fprintf (stderr, "Executing:");
+      for (p = argv; *p; p++)
+        fprintf (stderr, " '%s'", *p);
+      fprintf (stderr, "\n");
+    }
+
+  err = gnupg_spawn_process (argv[0], (const char **) &argv[1],
+                             GPG_ERR_SOURCE_DEFAULT,
+                             NULL,
+                             flags,
+                             &infp, &outfp, &errfp, &pid);
+  xfree (argv);
+#define IMC(A, B)                                                       \
+  _cons (sc, sc->vptr->mk_integer (sc, (unsigned long) (A)), (B), 1)
+#define IMS(A, B)                                                       \
+  _cons (sc, es_wrap (sc, (A)), (B), 1)
+  FFI_RETURN_POINTER (sc, IMS (infp,
+                              IMS (outfp,
+                                   IMS (errfp,
+                                        IMC (pid, sc->NIL)))));
+#undef IMS
+#undef IMC
+}
+
+static pointer
+do_spawn_process_fd (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  pointer arguments;
+  char **argv;
+  size_t len;
+  int infd, outfd, errfd;
+
+  pid_t pid;
+
+  FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args);
+  FFI_ARG_OR_RETURN (sc, int, infd, number, args);
+  FFI_ARG_OR_RETURN (sc, int, outfd, number, args);
+  FFI_ARG_OR_RETURN (sc, int, errfd, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  err = ffi_list2argv (sc, arguments, &argv, &len);
+  if (err == gpg_error (GPG_ERR_INV_VALUE))
+    return ffi_sprintf (sc, "%luth element of first argument is "
+                        "neither string nor symbol",
+                        (unsigned long) len);
+  if (err)
+    FFI_RETURN_ERR (sc, err);
+
+  if (verbose > 1)
+    {
+      char **p;
+      fprintf (stderr, "Executing:");
+      for (p = argv; *p; p++)
+        fprintf (stderr, " '%s'", *p);
+      fprintf (stderr, "\n");
+    }
+
+  err = gnupg_spawn_process_fd (argv[0], (const char **) &argv[1],
+                                infd, outfd, errfd, &pid);
+  xfree (argv);
+  FFI_RETURN_INT (sc, pid);
+}
+
+static pointer
+do_wait_process (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  const char *name;
+  pid_t pid;
+  int hang;
+
+  int retcode;
+
+  FFI_ARG_OR_RETURN (sc, const char *, name, string, args);
+  FFI_ARG_OR_RETURN (sc, pid_t, pid, number, args);
+  FFI_ARG_OR_RETURN (sc, int, hang, bool, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  err = gnupg_wait_process (name, pid, hang, &retcode);
+  if (err == GPG_ERR_GENERAL)
+    err = 0;   /* Let the return code speak for itself.  */
+
+  FFI_RETURN_INT (sc, retcode);
+}
+
+
+static pointer
+do_wait_processes (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  pointer list_names;
+  char **names;
+  pointer list_pids;
+  size_t i, count;
+  pid_t *pids;
+  int hang;
+  int *retcodes;
+  pointer retcodes_list = sc->NIL;
+
+  FFI_ARG_OR_RETURN (sc, pointer, list_names, list, args);
+  FFI_ARG_OR_RETURN (sc, pointer, list_pids, list, args);
+  FFI_ARG_OR_RETURN (sc, int, hang, bool, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  if (sc->vptr->list_length (sc, list_names)
+      != sc->vptr->list_length (sc, list_pids))
+    return
+      sc->vptr->mk_string (sc, "length of first two arguments must match");
+
+  err = ffi_list2argv (sc, list_names, &names, &count);
+  if (err == gpg_error (GPG_ERR_INV_VALUE))
+    return ffi_sprintf (sc, "%luth element of first argument is "
+                        "neither string nor symbol",
+                        (unsigned long) count);
+  if (err)
+    FFI_RETURN_ERR (sc, err);
+
+  err = ffi_list2intv (sc, list_pids, (int **) &pids, &count);
+  if (err == gpg_error (GPG_ERR_INV_VALUE))
+    return ffi_sprintf (sc, "%luth element of second argument is "
+                        "neither string nor symbol",
+                        (unsigned long) count);
+  if (err)
+    FFI_RETURN_ERR (sc, err);
+
+  retcodes = xtrycalloc (sizeof *retcodes, count);
+  if (retcodes == NULL)
+    {
+      xfree (names);
+      xfree (pids);
+      FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+    }
+
+  err = gnupg_wait_processes ((const char **) names, pids, count, hang,
+                              retcodes);
+  if (err == GPG_ERR_GENERAL)
+    err = 0;   /* Let the return codes speak.  */
+
+  for (i = 0; i < count; i++)
+    retcodes_list =
+      (sc->vptr->cons) (sc,
+                        sc->vptr->mk_integer (sc,
+                                              (long) retcodes[count-1-i]),
+                        retcodes_list);
+
+  xfree (names);
+  xfree (pids);
+  xfree (retcodes);
+  FFI_RETURN_POINTER (sc, retcodes_list);
+}
+
+
+static pointer
+do_pipe (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int filedes[2];
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  err = gnupg_create_pipe (filedes);
+#define IMC(A, B)                                                       \
+  _cons (sc, sc->vptr->mk_integer (sc, (unsigned long) (A)), (B), 1)
+  FFI_RETURN_POINTER (sc, IMC (filedes[0],
+                              IMC (filedes[1], sc->NIL)));
+#undef IMC
+}
+
+static pointer
+do_inbound_pipe (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int filedes[2];
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  err = gnupg_create_inbound_pipe (filedes, NULL, 0);
+#define IMC(A, B)                                                       \
+  _cons (sc, sc->vptr->mk_integer (sc, (unsigned long) (A)), (B), 1)
+  FFI_RETURN_POINTER (sc, IMC (filedes[0],
+                              IMC (filedes[1], sc->NIL)));
+#undef IMC
+}
+
+static pointer
+do_outbound_pipe (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int filedes[2];
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  err = gnupg_create_outbound_pipe (filedes, NULL, 0);
+#define IMC(A, B)                                                       \
+  _cons (sc, sc->vptr->mk_integer (sc, (unsigned long) (A)), (B), 1)
+  FFI_RETURN_POINTER (sc, IMC (filedes[0],
+                              IMC (filedes[1], sc->NIL)));
+#undef IMC
+}
+
+\f
+
+/* Test helper functions.  */
+static pointer
+do_file_equal (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  pointer result = sc->F;
+  char *a_name, *b_name;
+  int binary;
+  const char *mode;
+  FILE *a_stream = NULL, *b_stream = NULL;
+  struct stat a_stat, b_stat;
+#define BUFFER_SIZE    1024
+  char a_buf[BUFFER_SIZE], b_buf[BUFFER_SIZE];
+#undef BUFFER_SIZE
+  size_t chunk;
+
+  FFI_ARG_OR_RETURN (sc, char *, a_name, string, args);
+  FFI_ARG_OR_RETURN (sc, char *, b_name, string, args);
+  FFI_ARG_OR_RETURN (sc, int, binary, bool, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  mode = binary ? "rb" : "r";
+  a_stream = fopen (a_name, mode);
+  if (a_stream == NULL)
+    goto errout;
+
+  b_stream = fopen (b_name, mode);
+  if (b_stream == NULL)
+    goto errout;
+
+  if (fstat (fileno (a_stream), &a_stat) < 0)
+    goto errout;
+
+  if (fstat (fileno (b_stream), &b_stat) < 0)
+    goto errout;
+
+  if (binary && a_stat.st_size != b_stat.st_size)
+    {
+      if (verbose)
+        fprintf (stderr, "Files %s and %s differ in size %lu != %lu\n",
+                 a_name, b_name, (unsigned long) a_stat.st_size,
+                 (unsigned long) b_stat.st_size);
+
+      goto out;
+    }
+
+  while (! feof (a_stream))
+    {
+      chunk = sizeof a_buf;
+
+      chunk = fread (a_buf, 1, chunk, a_stream);
+      if (chunk == 0 && ferror (a_stream))
+        goto errout;   /* some error */
+
+      if (fread (b_buf, 1, chunk, b_stream) < chunk)
+        {
+          if (feof (b_stream))
+            goto out;  /* short read */
+          goto errout; /* some error */
+        }
+
+      if (chunk > 0 && memcmp (a_buf, b_buf, chunk) != 0)
+        goto out;
+    }
+
+  fread (b_buf, 1, 1, b_stream);
+  if (! feof (b_stream))
+    goto out;  /* b is longer */
+
+  /* They match.  */
+  result = sc->T;
+
+ out:
+  if (a_stream)
+    fclose (a_stream);
+  if (b_stream)
+    fclose (b_stream);
+  FFI_RETURN_POINTER (sc, result);
+ errout:
+  err = gpg_error_from_syserror ();
+  goto out;
+}
+
+static pointer
+do_splice (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  int source;
+  int sink;
+  ssize_t len = -1;
+  char buffer[1024];
+  ssize_t bytes_read;
+  FFI_ARG_OR_RETURN (sc, int, source, number, args);
+  FFI_ARG_OR_RETURN (sc, int, sink, number, args);
+  if (args != sc->NIL)
+    FFI_ARG_OR_RETURN (sc, ssize_t, len, number, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  while (len == -1 || len > 0)
+    {
+      size_t want = sizeof buffer;
+      if (len > 0 && (ssize_t) want > len)
+        want = (size_t) len;
+
+      bytes_read = read (source, buffer, want);
+      if (bytes_read == 0)
+        break;
+      if (bytes_read < 0)
+        FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+      if (write (sink, buffer, bytes_read) != bytes_read)
+        FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
+      if (len != -1)
+        len -= bytes_read;
+    }
+  FFI_RETURN (sc);
+}
+
+static pointer
+do_string_index (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *haystack;
+  char needle;
+  ssize_t offset = 0;
+  char *position;
+  FFI_ARG_OR_RETURN (sc, char *, haystack, string, args);
+  FFI_ARG_OR_RETURN (sc, char, needle, character, args);
+  if (args != sc->NIL)
+    {
+      FFI_ARG_OR_RETURN (sc, ssize_t, offset, number, args);
+      if (offset < 0)
+        return ffi_sprintf (sc, "offset must be positive");
+      if (offset > strlen (haystack))
+        return ffi_sprintf (sc, "offset exceeds haystack");
+    }
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  position = strchr (haystack+offset, needle);
+  if (position)
+    FFI_RETURN_INT (sc, position - haystack);
+  else
+    FFI_RETURN_POINTER (sc, sc->F);
+}
+
+static pointer
+do_string_rindex (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *haystack;
+  char needle;
+  ssize_t offset = 0;
+  char *position;
+  FFI_ARG_OR_RETURN (sc, char *, haystack, string, args);
+  FFI_ARG_OR_RETURN (sc, char, needle, character, args);
+  if (args != sc->NIL)
+    {
+      FFI_ARG_OR_RETURN (sc, ssize_t, offset, number, args);
+      if (offset < 0)
+        return ffi_sprintf (sc, "offset must be positive");
+      if (offset > strlen (haystack))
+        return ffi_sprintf (sc, "offset exceeds haystack");
+    }
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  position = strrchr (haystack+offset, needle);
+  if (position)
+    FFI_RETURN_INT (sc, position - haystack);
+  else
+    FFI_RETURN_POINTER (sc, sc->F);
+}
+
+static pointer
+do_string_contains (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  char *haystack;
+  char *needle;
+  FFI_ARG_OR_RETURN (sc, char *, haystack, string, args);
+  FFI_ARG_OR_RETURN (sc, char *, needle, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+  FFI_RETURN_POINTER (sc, strstr (haystack, needle) ? sc->T : sc->F);
+}
+
+static pointer
+do_glob (scheme *sc, pointer args)
+{
+  FFI_PROLOG ();
+  pointer result = sc->NIL;
+  size_t i;
+  char *pattern;
+  glob_t pglob;
+  FFI_ARG_OR_RETURN (sc, char *, pattern, string, args);
+  FFI_ARGS_DONE_OR_RETURN (sc, args);
+
+  switch (glob (pattern, 0, NULL, &pglob))
+    {
+    case 0:
+      for (i = 0; i < pglob.gl_pathc; i++)
+        result =
+          (sc->vptr->cons) (sc,
+                            sc->vptr->mk_string (sc, pglob.gl_pathv[i]),
+                            result);
+      globfree (&pglob);
+      break;
+
+    case GLOB_NOMATCH:
+      /* Return the empty list.  */
+      break;
+
+    case GLOB_NOSPACE:
+      return ffi_sprintf (sc, "out of memory");
+    case GLOB_ABORTED:
+      return ffi_sprintf (sc, "read error");
+    default:
+      assert (! "not reached");
+    }
+  FFI_RETURN_POINTER (sc, result);
+}
+
+\f
+gpg_error_t
+ffi_list2argv (scheme *sc, pointer list, char ***argv, size_t *len)
+{
+  int i;
+
+  *len = sc->vptr->list_length (sc, list);
+  *argv = xtrycalloc (*len + 1, sizeof **argv);
+  if (*argv == NULL)
+    return gpg_error_from_syserror ();
+
+  for (i = 0; sc->vptr->is_pair (list); list = sc->vptr->pair_cdr (list))
+    {
+      if (sc->vptr->is_string (sc->vptr->pair_car (list)))
+        (*argv)[i++] = sc->vptr->string_value (sc->vptr->pair_car (list));
+      else if (sc->vptr->is_symbol (sc->vptr->pair_car (list)))
+        (*argv)[i++] = sc->vptr->symname (sc->vptr->pair_car (list));
+      else
+        {
+          xfree (*argv);
+          *argv = NULL;
+          *len = i;
+          return gpg_error (GPG_ERR_INV_VALUE);
+        }
+    }
+  (*argv)[i] = NULL;
+  return 0;
+}
+
+gpg_error_t
+ffi_list2intv (scheme *sc, pointer list, int **intv, size_t *len)
+{
+  int i;
+
+  *len = sc->vptr->list_length (sc, list);
+  *intv = xtrycalloc (*len, sizeof **intv);
+  if (*intv == NULL)
+    return gpg_error_from_syserror ();
+
+  for (i = 0; sc->vptr->is_pair (list); list = sc->vptr->pair_cdr (list))
+    {
+      if (sc->vptr->is_number (sc->vptr->pair_car (list)))
+        (*intv)[i++] = sc->vptr->ivalue (sc->vptr->pair_car (list));
+      else
+        {
+          xfree (*intv);
+          *intv = NULL;
+          *len = i;
+          return gpg_error (GPG_ERR_INV_VALUE);
+        }
+    }
+
+  return 0;
+}
+
+\f
+char *
+ffi_schemify_name (const char *s, int macro)
+{
+  /* Fixme: We should use xtrystrdup and return NULL.  However, this
+   * requires a lot more changes.  Simply returning S as done
+   * originally is not an option.  */
+  char *n = xstrdup (s), *p;
+  /* if (n == NULL) */
+  /*   return s; */
+
+  for (p = n; *p; p++)
+    {
+      *p = (char) tolower (*p);
+       /* We convert _ to - in identifiers.  We allow, however, for
+         function names to start with a leading _.  The functions in
+         this namespace are not yet finalized and might change or
+         vanish without warning.  Use them with care.  */
+      if (! macro
+         && p != n
+         && *p == '_')
+       *p = '-';
+    }
+  return n;
+}
+
+pointer
+ffi_sprintf (scheme *sc, const char *format, ...)
+{
+  pointer result;
+  va_list listp;
+  char *expression;
+  int size, written;
+
+  va_start (listp, format);
+  size = vsnprintf (NULL, 0, format, listp);
+  va_end (listp);
+
+  expression = xtrymalloc (size + 1);
+  if (expression == NULL)
+    return NULL;
+
+  va_start (listp, format);
+  written = vsnprintf (expression, size + 1, format, listp);
+  va_end (listp);
+
+  assert (size == written);
+
+  result = sc->vptr->mk_string (sc, expression);
+  xfree (expression);
+  return result;
+}
+
+void
+ffi_scheme_eval (scheme *sc, const char *format, ...)
+{
+  va_list listp;
+  char *expression;
+  int size, written;
+
+  va_start (listp, format);
+  size = vsnprintf (NULL, 0, format, listp);
+  va_end (listp);
+
+  expression = xtrymalloc (size + 1);
+  if (expression == NULL)
+    return;
+
+  va_start (listp, format);
+  written = vsnprintf (expression, size + 1, format, listp);
+  va_end (listp);
+
+  assert (size == written);
+
+  sc->vptr->load_string (sc, expression);
+  xfree (expression);
+}
+
+gpg_error_t
+ffi_init (scheme *sc, const char *argv0, int argc, const char **argv)
+{
+  int i;
+  pointer args = sc->NIL;
+
+  /* bitwise arithmetic */
+  ffi_define_function (sc, logand);
+  ffi_define_function (sc, logior);
+  ffi_define_function (sc, logxor);
+  ffi_define_function (sc, lognot);
+
+  /* libc.  */
+  ffi_define_constant (sc, O_RDONLY);
+  ffi_define_constant (sc, O_WRONLY);
+  ffi_define_constant (sc, O_RDWR);
+  ffi_define_constant (sc, O_CREAT);
+  ffi_define_constant (sc, O_APPEND);
+#ifndef O_BINARY
+# define O_BINARY      0
+#endif
+#ifndef O_TEXT
+# define O_TEXT                0
+#endif
+  ffi_define_constant (sc, O_BINARY);
+  ffi_define_constant (sc, O_TEXT);
+  ffi_define_constant (sc, STDIN_FILENO);
+  ffi_define_constant (sc, STDOUT_FILENO);
+  ffi_define_constant (sc, STDERR_FILENO);
+
+  ffi_define_function (sc, sleep);
+  ffi_define_function (sc, usleep);
+  ffi_define_function (sc, chdir);
+  ffi_define_function (sc, strerror);
+  ffi_define_function (sc, getenv);
+  ffi_define_function (sc, setenv);
+  ffi_define_function (sc, exit);
+  ffi_define_function (sc, open);
+  ffi_define_function (sc, fdopen);
+  ffi_define_function (sc, close);
+  ffi_define_function (sc, mkdtemp);
+  ffi_define_function (sc, unlink);
+  ffi_define_function (sc, unlink_recursively);
+  ffi_define_function (sc, rename);
+  ffi_define_function (sc, getcwd);
+  ffi_define_function (sc, mkdir);
+  ffi_define_function (sc, rmdir);
+
+  /* Process management.  */
+  ffi_define_function (sc, spawn_process);
+  ffi_define_function (sc, spawn_process_fd);
+  ffi_define_function (sc, wait_process);
+  ffi_define_function (sc, wait_processes);
+  ffi_define_function (sc, pipe);
+  ffi_define_function (sc, inbound_pipe);
+  ffi_define_function (sc, outbound_pipe);
+
+  /* estream functions.  */
+  ffi_define_function_name (sc, "es-fclose", es_fclose);
+  ffi_define_function_name (sc, "es-read", es_read);
+  ffi_define_function_name (sc, "es-feof", es_feof);
+  ffi_define_function_name (sc, "es-write", es_write);
+
+  /* Test helper functions.  */
+  ffi_define_function (sc, file_equal);
+  ffi_define_function (sc, splice);
+  ffi_define_function (sc, string_index);
+  ffi_define_function (sc, string_rindex);
+  ffi_define_function_name (sc, "string-contains?", string_contains);
+  ffi_define_function (sc, glob);
+
+  /* User interface.  */
+  ffi_define_function (sc, flush_stdio);
+  ffi_define_function (sc, prompt);
+
+  /* Configuration.  */
+  ffi_define (sc, "*verbose*", sc->vptr->mk_integer (sc, verbose));
+
+  ffi_define (sc, "*argv0*", sc->vptr->mk_string (sc, argv0));
+  for (i = argc - 1; i >= 0; i--)
+    {
+      pointer value = sc->vptr->mk_string (sc, argv[i]);
+      args = (sc->vptr->cons) (sc, value, args);
+    }
+  ffi_define (sc, "*args*", args);
+
+#if _WIN32
+  ffi_define (sc, "*pathsep*", sc->vptr->mk_character (sc, ';'));
+#else
+  ffi_define (sc, "*pathsep*", sc->vptr->mk_character (sc, ':'));
+#endif
+
+  ffi_define (sc, "*stdin*",
+              sc->vptr->mk_port_from_file (sc, stdin, port_input));
+  ffi_define (sc, "*stdout*",
+              sc->vptr->mk_port_from_file (sc, stdout, port_output));
+  ffi_define (sc, "*stderr*",
+              sc->vptr->mk_port_from_file (sc, stderr, port_output));
+
+  return 0;
+}
diff --git a/tests/gpgscm/ffi.h b/tests/gpgscm/ffi.h
new file mode 100644 (file)
index 0000000..02dd99d
--- /dev/null
@@ -0,0 +1,30 @@
+/* FFI interface for TinySCHEME.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GPGSCM_FFI_H
+#define GPGSCM_FFI_H
+
+#include <gpg-error.h>
+#include "scheme.h"
+
+gpg_error_t ffi_init (scheme *sc, const char *argv0,
+                     int argc, const char **argv);
+
+#endif /* GPGSCM_FFI_H */
diff --git a/tests/gpgscm/ffi.scm b/tests/gpgscm/ffi.scm
new file mode 100644 (file)
index 0000000..7c2f93a
--- /dev/null
@@ -0,0 +1,44 @@
+;; FFI interface for TinySCHEME.
+;;
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+;; Foreign function wrapper.  Expects F to return a list with the
+;; first element being the `error_t' value returned by the foreign
+;; function.  The error is thrown, or the cdr of the result is
+;; returned.
+(define (ffi-apply name f args)
+  (let ((result (apply f args)))
+    (cond
+     ((string? result)
+      (ffi-fail name args result))
+     ((not (= (car result) 0))
+      (ffi-fail name args (strerror (car result))))
+     ((and (= (car result) 0) (pair? (cdr result))) (cadr result))
+     ((= (car result) 0) '())
+     (else
+      (throw (list "Result violates FFI calling convention: " result))))))
+
+(define (ffi-fail name args message)
+  (let ((args' (open-output-string)))
+    (write (cons (string->symbol name) args) args')
+    (throw (string-append
+           (get-output-string args') ": " message))))
+
+;; Pseudo-definitions for foreign functions.  Evaluates to no code,
+;; but serves as documentation.
+(macro (ffi-define form))
diff --git a/tests/gpgscm/init.scm b/tests/gpgscm/init.scm
new file mode 100644 (file)
index 0000000..0889366
--- /dev/null
@@ -0,0 +1,723 @@
+;    Initialization file for TinySCHEME 1.41
+
+; Per R5RS, up to four deep compositions should be defined
+(define (caar x) (car (car x)))
+(define (cadr x) (car (cdr x)))
+(define (cdar x) (cdr (car x)))
+(define (cddr x) (cdr (cdr x)))
+(define (caaar x) (car (car (car x))))
+(define (caadr x) (car (car (cdr x))))
+(define (cadar x) (car (cdr (car x))))
+(define (caddr x) (car (cdr (cdr x))))
+(define (cdaar x) (cdr (car (car x))))
+(define (cdadr x) (cdr (car (cdr x))))
+(define (cddar x) (cdr (cdr (car x))))
+(define (cdddr x) (cdr (cdr (cdr x))))
+(define (caaaar x) (car (car (car (car x)))))
+(define (caaadr x) (car (car (car (cdr x)))))
+(define (caadar x) (car (car (cdr (car x)))))
+(define (caaddr x) (car (car (cdr (cdr x)))))
+(define (cadaar x) (car (cdr (car (car x)))))
+(define (cadadr x) (car (cdr (car (cdr x)))))
+(define (caddar x) (car (cdr (cdr (car x)))))
+(define (cadddr x) (car (cdr (cdr (cdr x)))))
+(define (cdaaar x) (cdr (car (car (car x)))))
+(define (cdaadr x) (cdr (car (car (cdr x)))))
+(define (cdadar x) (cdr (car (cdr (car x)))))
+(define (cdaddr x) (cdr (car (cdr (cdr x)))))
+(define (cddaar x) (cdr (cdr (car (car x)))))
+(define (cddadr x) (cdr (cdr (car (cdr x)))))
+(define (cdddar x) (cdr (cdr (cdr (car x)))))
+(define (cddddr x) (cdr (cdr (cdr (cdr x)))))
+
+;;;; Utility to ease macro creation
+(define (macro-expand form)
+     ((eval (get-closure-code (eval (car form)))) form))
+
+(define (macro-expand-all form)
+   (if (macro? form)
+      (macro-expand-all (macro-expand form))
+      form))
+
+(define *compile-hook* macro-expand-all)
+
+
+(macro (unless form)
+     `(if (not ,(cadr form)) (begin ,@(cddr form))))
+
+(macro (when form)
+     `(if ,(cadr form) (begin ,@(cddr form))))
+
+; DEFINE-MACRO Contributed by Andy Gaynor
+(macro (define-macro dform)
+  (if (symbol? (cadr dform))
+    `(macro ,@(cdr dform))
+    (let ((form (gensym)))
+      `(macro (,(caadr dform) ,form)
+         (apply (lambda ,(cdadr dform) ,@(cddr dform)) (cdr ,form))))))
+
+; Utilities for math. Notice that inexact->exact is primitive,
+; but exact->inexact is not.
+(define exact? integer?)
+(define (inexact? x) (and (real? x) (not (integer? x))))
+(define (even? n) (= (remainder n 2) 0))
+(define (odd? n) (not (= (remainder n 2) 0)))
+(define (zero? n) (= n 0))
+(define (positive? n) (> n 0))
+(define (negative? n) (< n 0))
+(define complex? number?)
+(define rational? real?)
+(define (abs n) (if (>= n 0) n (- n)))
+(define (exact->inexact n) (* n 1.0))
+(define (<> n1 n2) (not (= n1 n2)))
+
+; min and max must return inexact if any arg is inexact; use (+ n 0.0)
+(define (max . lst)
+  (foldr (lambda (a b)
+           (if (> a b)
+             (if (exact? b) a (+ a 0.0))
+             (if (exact? a) b (+ b 0.0))))
+         (car lst) (cdr lst)))
+(define (min . lst)
+  (foldr (lambda (a b)
+           (if (< a b)
+             (if (exact? b) a (+ a 0.0))
+             (if (exact? a) b (+ b 0.0))))
+         (car lst) (cdr lst)))
+
+(define (succ x) (+ x 1))
+(define (pred x) (- x 1))
+(define gcd
+  (lambda a
+    (if (null? a)
+      0
+      (let ((aa (abs (car a)))
+            (bb (abs (cadr a))))
+         (if (= bb 0)
+              aa
+              (gcd bb (remainder aa bb)))))))
+(define lcm
+  (lambda a
+    (if (null? a)
+      1
+      (let ((aa (abs (car a)))
+            (bb (abs (cadr a))))
+         (if (or (= aa 0) (= bb 0))
+             0
+             (abs (* (quotient aa (gcd aa bb)) bb)))))))
+
+
+(define (string . charlist)
+     (list->string charlist))
+
+(define (list->string charlist)
+     (let* ((len (length charlist))
+            (newstr (make-string len))
+            (fill-string!
+               (lambda (str i len charlist)
+                    (if (= i len)
+                         str
+                         (begin (string-set! str i (car charlist))
+                         (fill-string! str (+ i 1) len (cdr charlist)))))))
+          (fill-string! newstr 0 len charlist)))
+
+(define (string-fill! s e)
+     (let ((n (string-length s)))
+          (let loop ((i 0))
+               (if (= i n)
+                    s
+                    (begin (string-set! s i e) (loop (succ i)))))))
+
+(define (string->list s)
+     (let loop ((n (pred (string-length s))) (l '()))
+          (if (= n -1)
+               l
+               (loop (pred n) (cons (string-ref s n) l)))))
+
+(define (string-copy str)
+     (string-append str))
+
+(define (string->anyatom str pred)
+     (let* ((a (string->atom str)))
+       (if (pred a) a
+         (error "string->xxx: not a xxx" a))))
+
+(define (string->number str . base)
+    (let ((n (string->atom str (if (null? base) 10 (car base)))))
+        (if (number? n) n #f)))
+
+(define (anyatom->string n pred)
+  (if (pred n)
+      (atom->string n)
+      (error "xxx->string: not a xxx" n)))
+
+(define (number->string n . base)
+    (atom->string n (if (null? base) 10 (car base))))
+
+
+(define (char-cmp? cmp a b)
+     (cmp (char->integer a) (char->integer b)))
+(define (char-ci-cmp? cmp a b)
+     (cmp (char->integer (char-downcase a)) (char->integer (char-downcase b))))
+
+(define (char=? a b) (char-cmp? = a b))
+(define (char<? a b) (char-cmp? < a b))
+(define (char>? a b) (char-cmp? > a b))
+(define (char<=? a b) (char-cmp? <= a b))
+(define (char>=? a b) (char-cmp? >= a b))
+
+(define (char-ci=? a b) (char-ci-cmp? = a b))
+(define (char-ci<? a b) (char-ci-cmp? < a b))
+(define (char-ci>? a b) (char-ci-cmp? > a b))
+(define (char-ci<=? a b) (char-ci-cmp? <= a b))
+(define (char-ci>=? a b) (char-ci-cmp? >= a b))
+
+; Note the trick of returning (cmp x y)
+(define (string-cmp? chcmp cmp a b)
+     (let ((na (string-length a)) (nb (string-length b)))
+          (let loop ((i 0))
+               (cond
+                    ((= i na)
+                         (if (= i nb) (cmp 0 0) (cmp 0 1)))
+                    ((= i nb)
+                         (cmp 1 0))
+                    ((chcmp = (string-ref a i) (string-ref b i))
+                         (loop (succ i)))
+                    (else
+                         (chcmp cmp (string-ref a i) (string-ref b i)))))))
+
+
+(define (string=? a b) (string-cmp? char-cmp? = a b))
+(define (string<? a b) (string-cmp? char-cmp? < a b))
+(define (string>? a b) (string-cmp? char-cmp? > a b))
+(define (string<=? a b) (string-cmp? char-cmp? <= a b))
+(define (string>=? a b) (string-cmp? char-cmp? >= a b))
+
+(define (string-ci=? a b) (string-cmp? char-ci-cmp? = a b))
+(define (string-ci<? a b) (string-cmp? char-ci-cmp? < a b))
+(define (string-ci>? a b) (string-cmp? char-ci-cmp? > a b))
+(define (string-ci<=? a b) (string-cmp? char-ci-cmp? <= a b))
+(define (string-ci>=? a b) (string-cmp? char-ci-cmp? >= a b))
+
+(define (list . x) x)
+
+(define (foldr f x lst)
+     (if (null? lst)
+          x
+          (foldr f (f x (car lst)) (cdr lst))))
+
+(define (unzip1-with-cdr . lists)
+  (unzip1-with-cdr-iterative lists '() '()))
+
+(define (unzip1-with-cdr-iterative lists cars cdrs)
+  (if (null? lists)
+      (cons cars cdrs)
+      (let ((car1 (caar lists))
+            (cdr1 (cdar lists)))
+        (unzip1-with-cdr-iterative
+          (cdr lists)
+          (append cars (list car1))
+          (append cdrs (list cdr1))))))
+
+(define (map proc . lists)
+  (if (null? lists)
+      (apply proc)
+      (if (null? (car lists))
+        '()
+        (let* ((unz (apply unzip1-with-cdr lists))
+               (cars (car unz))
+               (cdrs (cdr unz)))
+          (cons (apply proc cars) (apply map (cons proc cdrs)))))))
+
+(define (for-each proc . lists)
+  (if (null? lists)
+      (apply proc)
+      (if (null? (car lists))
+        #t
+        (let* ((unz (apply unzip1-with-cdr lists))
+               (cars (car unz))
+               (cdrs (cdr unz)))
+          (apply proc cars) (apply map (cons proc cdrs))))))
+
+(define (list-tail x k)
+    (if (zero? k)
+        x
+        (list-tail (cdr x) (- k 1))))
+
+(define (list-ref x k)
+    (car (list-tail x k)))
+
+(define (last-pair x)
+    (if (pair? (cdr x))
+        (last-pair (cdr x))
+        x))
+
+(define (head stream) (car stream))
+
+(define (tail stream) (force (cdr stream)))
+
+(define (vector-equal? x y)
+     (and (vector? x) (vector? y) (= (vector-length x) (vector-length y))
+          (let ((n (vector-length x)))
+               (let loop ((i 0))
+                    (if (= i n)
+                         #t
+                         (and (equal? (vector-ref x i) (vector-ref y i))
+                              (loop (succ i))))))))
+
+(define (list->vector x)
+     (apply vector x))
+
+(define (vector-fill! v e)
+     (let ((n (vector-length v)))
+          (let loop ((i 0))
+               (if (= i n)
+                    v
+                    (begin (vector-set! v i e) (loop (succ i)))))))
+
+(define (vector->list v)
+     (let loop ((n (pred (vector-length v))) (l '()))
+          (if (= n -1)
+               l
+               (loop (pred n) (cons (vector-ref v n) l)))))
+
+;; The following quasiquote macro is due to Eric S. Tiedemann.
+;;   Copyright 1988 by Eric S. Tiedemann; all rights reserved.
+;;
+;; Subsequently modified to handle vectors: D. Souflis
+
+(macro
+ quasiquote
+ (lambda (l)
+   (define (mcons f l r)
+     (if (and (pair? r)
+              (eq? (car r) 'quote)
+              (eq? (car (cdr r)) (cdr f))
+              (pair? l)
+              (eq? (car l) 'quote)
+              (eq? (car (cdr l)) (car f)))
+         (if (or (procedure? f) (number? f) (string? f))
+               f
+               (list 'quote f))
+         (if (eqv? l vector)
+               (apply l (eval r))
+               (list 'cons l r)
+               )))
+   (define (mappend f l r)
+     (if (or (null? (cdr f))
+             (and (pair? r)
+                  (eq? (car r) 'quote)
+                  (eq? (car (cdr r)) '())))
+         l
+         (list 'append l r)))
+   (define (foo level form)
+     (cond ((not (pair? form))
+               (if (or (procedure? form) (number? form) (string? form))
+                    form
+                    (list 'quote form))
+               )
+           ((eq? 'quasiquote (car form))
+            (mcons form ''quasiquote (foo (+ level 1) (cdr form))))
+           (#t (if (zero? level)
+                   (cond ((eq? (car form) 'unquote) (car (cdr form)))
+                         ((eq? (car form) 'unquote-splicing)
+                          (error "Unquote-splicing wasn't in a list:"
+                                 form))
+                         ((and (pair? (car form))
+                               (eq? (car (car form)) 'unquote-splicing))
+                          (mappend form (car (cdr (car form)))
+                                   (foo level (cdr form))))
+                         (#t (mcons form (foo level (car form))
+                                         (foo level (cdr form)))))
+                   (cond ((eq? (car form) 'unquote)
+                          (mcons form ''unquote (foo (- level 1)
+                                                     (cdr form))))
+                         ((eq? (car form) 'unquote-splicing)
+                          (mcons form ''unquote-splicing
+                                      (foo (- level 1) (cdr form))))
+                         (#t (mcons form (foo level (car form))
+                                         (foo level (cdr form)))))))))
+   (foo 0 (car (cdr l)))))
+
+;;;;;Helper for the dynamic-wind definition.  By Tom Breton (Tehom)
+(define (shared-tail x y)
+   (let ((len-x (length x))
+         (len-y (length y)))
+      (define (shared-tail-helper x y)
+         (if
+            (eq? x y)
+            x
+            (shared-tail-helper (cdr x) (cdr y))))
+
+      (cond
+         ((> len-x len-y)
+            (shared-tail-helper
+               (list-tail x (- len-x len-y))
+               y))
+         ((< len-x len-y)
+            (shared-tail-helper
+               x
+               (list-tail y (- len-y len-x))))
+         (#t (shared-tail-helper x y)))))
+
+;;;;;Dynamic-wind by Tom Breton (Tehom)
+
+;;Guarded because we must only eval this once, because doing so
+;;redefines call/cc in terms of old call/cc
+(unless (defined? 'dynamic-wind)
+   (let
+      ;;These functions are defined in the context of a private list of
+      ;;pairs of before/after procs.
+      (  (*active-windings* '())
+         ;;We'll define some functions into the larger environment, so
+         ;;we need to know it.
+         (outer-env (current-environment)))
+
+      ;;Poor-man's structure operations
+      (define before-func car)
+      (define after-func  cdr)
+      (define make-winding cons)
+
+      ;;Manage active windings
+      (define (activate-winding! new)
+         ((before-func new))
+         (set! *active-windings* (cons new *active-windings*)))
+      (define (deactivate-top-winding!)
+         (let ((old-top (car *active-windings*)))
+            ;;Remove it from the list first so it's not active during its
+            ;;own exit.
+            (set! *active-windings* (cdr *active-windings*))
+            ((after-func old-top))))
+
+      (define (set-active-windings! new-ws)
+         (unless (eq? new-ws *active-windings*)
+            (let ((shared (shared-tail new-ws *active-windings*)))
+
+               ;;Define the looping functions.
+               ;;Exit the old list.  Do deeper ones last.  Don't do
+               ;;any shared ones.
+               (define (pop-many)
+                  (unless (eq? *active-windings* shared)
+                     (deactivate-top-winding!)
+                     (pop-many)))
+               ;;Enter the new list.  Do deeper ones first so that the
+               ;;deeper windings will already be active.  Don't do any
+               ;;shared ones.
+               (define (push-many new-ws)
+                  (unless (eq? new-ws shared)
+                     (push-many (cdr new-ws))
+                     (activate-winding! (car new-ws))))
+
+               ;;Do it.
+               (pop-many)
+               (push-many new-ws))))
+
+      ;;The definitions themselves.
+      (eval
+         `(define call-with-current-continuation
+             ;;It internally uses the built-in call/cc, so capture it.
+             ,(let ((old-c/cc call-with-current-continuation))
+                 (lambda (func)
+                    ;;Use old call/cc to get the continuation.
+                    (old-c/cc
+                       (lambda (continuation)
+                          ;;Call func with not the continuation itself
+                          ;;but a procedure that adjusts the active
+                          ;;windings to what they were when we made
+                          ;;this, and only then calls the
+                          ;;continuation.
+                          (func
+                             (let ((current-ws *active-windings*))
+                                (lambda (x)
+                                   (set-active-windings! current-ws)
+                                   (continuation x)))))))))
+         outer-env)
+      ;;We can't just say "define (dynamic-wind before thunk after)"
+      ;;because the lambda it's defined to lives in this environment,
+      ;;not in the global environment.
+      (eval
+         `(define dynamic-wind
+             ,(lambda (before thunk after)
+                 ;;Make a new winding
+                 (activate-winding! (make-winding before after))
+                 (let ((result (thunk)))
+                    ;;Get rid of the new winding.
+                    (deactivate-top-winding!)
+                    ;;The return value is that of thunk.
+                    result)))
+         outer-env)))
+
+(define call/cc call-with-current-continuation)
+
+
+;;;;; atom? and equal? written by a.k
+
+;;;; atom?
+(define (atom? x)
+  (not (pair? x)))
+
+;;;;    equal?
+(define (equal? x y)
+     (cond
+          ((pair? x)
+               (and (pair? y)
+                    (equal? (car x) (car y))
+                    (equal? (cdr x) (cdr y))))
+          ((vector? x)
+               (and (vector? y) (vector-equal? x y)))
+          ((string? x)
+               (and (string? y) (string=? x y)))
+          (else (eqv? x y))))
+
+;;;; (do ((var init inc) ...) (endtest result ...) body ...)
+;;
+(macro do
+  (lambda (do-macro)
+    (apply (lambda (do vars endtest . body)
+             (let ((do-loop (gensym)))
+               `(letrec ((,do-loop
+                           (lambda ,(map (lambda (x)
+                                           (if (pair? x) (car x) x))
+                                      `,vars)
+                             (if ,(car endtest)
+                               (begin ,@(cdr endtest))
+                               (begin
+                                 ,@body
+                                 (,do-loop
+                                   ,@(map (lambda (x)
+                                            (cond
+                                              ((not (pair? x)) x)
+                                              ((< (length x) 3) (car x))
+                                              (else (car (cdr (cdr x))))))
+                                       `,vars)))))))
+                  (,do-loop
+                    ,@(map (lambda (x)
+                             (if (and (pair? x) (cdr x))
+                               (car (cdr x))
+                               '()))
+                        `,vars)))))
+      do-macro)))
+
+;;;; generic-member
+(define (generic-member cmp obj lst)
+  (cond
+    ((null? lst) #f)
+    ((cmp obj (car lst)) lst)
+    (else (generic-member cmp obj (cdr lst)))))
+
+(define (memq obj lst)
+     (generic-member eq? obj lst))
+(define (memv obj lst)
+     (generic-member eqv? obj lst))
+(define (member obj lst)
+     (generic-member equal? obj lst))
+
+;;;; generic-assoc
+(define (generic-assoc cmp obj alst)
+     (cond
+          ((null? alst) #f)
+          ((cmp obj (caar alst)) (car alst))
+          (else (generic-assoc cmp obj (cdr alst)))))
+
+(define (assq obj alst)
+     (generic-assoc eq? obj alst))
+(define (assv obj alst)
+     (generic-assoc eqv? obj alst))
+(define (assoc obj alst)
+     (generic-assoc equal? obj alst))
+
+(define (acons x y z) (cons (cons x y) z))
+
+;;;; Handy for imperative programs
+;;;; Used as: (define-with-return (foo x y) .... (return z) ...)
+(macro (define-with-return form)
+     `(define ,(cadr form)
+          (call/cc (lambda (return) ,@(cddr form)))))
+
+;;;; Simple exception handling
+;
+;    Exceptions are caught as follows:
+;
+;         (catch (do-something to-recover and-return meaningful-value)
+;              (if-something goes-wrong)
+;              (with-these calls))
+;
+;    "Catch" establishes a scope spanning multiple call-frames until
+;    another "catch" is encountered.  Within the recovery expression
+;    the thrown exception is bound to *error*.
+;
+;    Exceptions are thrown with:
+;
+;         (throw "message")
+;
+;    If used outside a (catch ...), reverts to (error "message)
+
+(define *handlers* (list))
+
+(define (push-handler proc)
+     (set! *handlers* (cons proc *handlers*)))
+
+(define (pop-handler)
+     (let ((h (car *handlers*)))
+          (set! *handlers* (cdr *handlers*))
+          h))
+
+(define (more-handlers?)
+     (pair? *handlers*))
+
+(define (throw . x)
+     (if (more-handlers?)
+          (apply (pop-handler) x)
+          (apply error x)))
+
+(macro (catch form)
+     (let ((label (gensym)))
+          `(call/cc (lambda (exit)
+               (push-handler (lambda (*error*) (exit ,(cadr form))))
+               (let ((,label (begin ,@(cddr form))))
+                    (pop-handler)
+                    ,label)))))
+
+(define (*error-hook* . args)
+  (throw args))
+
+
+;;;;; Definition of MAKE-ENVIRONMENT, to be used with two-argument EVAL
+
+(macro (make-environment form)
+     `(apply (lambda ()
+               ,@(cdr form)
+               (current-environment))))
+
+(define-macro (eval-polymorphic x . envl)
+  (display envl)
+  (let* ((env (if (null? envl) (current-environment) (eval (car envl))))
+         (xval (eval x env)))
+    (if (closure? xval)
+      (make-closure (get-closure-code xval) env)
+      xval)))
+
+; Redefine this if you install another package infrastructure
+; Also redefine 'package'
+(define *colon-hook* eval)
+
+(macro (package form)
+  `(apply (lambda ()
+           ,@(cdr form)
+           (current-environment))))
+
+;;;;; I/O
+
+(define (input-output-port? p)
+     (and (input-port? p) (output-port? p)))
+
+(define (close-port p)
+     (cond
+          ((input-output-port? p) (close-input-port p) (close-output-port p))
+          ((input-port? p) (close-input-port p))
+          ((output-port? p) (close-output-port p))
+          (else (throw "Not a port" p))))
+
+(define (call-with-input-file s p)
+     (let ((inport (open-input-file s)))
+          (if (eq? inport #f)
+               #f
+               (let ((res (p inport)))
+                    (close-input-port inport)
+                    res))))
+
+(define (call-with-output-file s p)
+     (let ((outport (open-output-file s)))
+          (if (eq? outport #f)
+               #f
+               (let ((res (p outport)))
+                    (close-output-port outport)
+                    res))))
+
+(define (with-input-from-file s p)
+     (let ((inport (open-input-file s)))
+          (if (eq? inport #f)
+               #f
+               (let ((prev-inport (current-input-port)))
+                    (set-input-port inport)
+                    (let ((res (p)))
+                         (close-input-port inport)
+                         (set-input-port prev-inport)
+                         res)))))
+
+(define (with-output-to-file s p)
+     (let ((outport (open-output-file s)))
+          (if (eq? outport #f)
+               #f
+               (let ((prev-outport (current-output-port)))
+                    (set-output-port outport)
+                    (let ((res (p)))
+                         (close-output-port outport)
+                         (set-output-port prev-outport)
+                         res)))))
+
+(define (with-input-output-from-to-files si so p)
+     (let ((inport (open-input-file si))
+           (outport (open-input-file so)))
+          (if (not (and inport outport))
+               (begin
+                    (close-input-port inport)
+                    (close-output-port outport)
+                    #f)
+               (let ((prev-inport (current-input-port))
+                     (prev-outport (current-output-port)))
+                    (set-input-port inport)
+                    (set-output-port outport)
+                    (let ((res (p)))
+                         (close-input-port inport)
+                         (close-output-port outport)
+                         (set-input-port prev-inport)
+                         (set-output-port prev-outport)
+                         res)))))
+
+; Random number generator (maximum cycle)
+(define *seed* 1)
+(define (random-next)
+     (let* ((a 16807) (m 2147483647) (q (quotient m a)) (r (modulo m a)))
+          (set! *seed*
+               (-   (* a (- *seed*
+                         (* (quotient *seed* q) q)))
+                    (* (quotient *seed* q) r)))
+          (if (< *seed* 0) (set! *seed* (+ *seed* m)))
+          *seed*))
+;; SRFI-0
+;; COND-EXPAND
+;; Implemented as a macro
+(define *features* '(srfi-0 tinyscheme))
+
+(define-macro (cond-expand . cond-action-list)
+  (cond-expand-runtime cond-action-list))
+
+(define (cond-expand-runtime cond-action-list)
+  (if (null? cond-action-list)
+      #t
+      (if (cond-eval (caar cond-action-list))
+          `(begin ,@(cdar cond-action-list))
+          (cond-expand-runtime (cdr cond-action-list)))))
+
+(define (cond-eval-and cond-list)
+  (foldr (lambda (x y) (and (cond-eval x) (cond-eval y))) #t cond-list))
+
+(define (cond-eval-or cond-list)
+  (foldr (lambda (x y) (or (cond-eval x) (cond-eval y))) #f cond-list))
+
+(define (cond-eval condition)
+  (cond
+    ((symbol? condition)
+       (if (member condition *features*) #t #f))
+    ((eq? condition #t) #t)
+    ((eq? condition #f) #f)
+    (else (case (car condition)
+            ((and) (cond-eval-and (cdr condition)))
+            ((or) (cond-eval-or (cdr condition)))
+            ((not) (if (not (null? (cddr condition)))
+                     (error "cond-expand : 'not' takes 1 argument")
+                     (not (cond-eval (cadr condition)))))
+            (else (error "cond-expand : unknown operator" (car condition)))))))
+
+(gc-verbose #f)
diff --git a/tests/gpgscm/lib.scm b/tests/gpgscm/lib.scm
new file mode 100644 (file)
index 0000000..e23977a
--- /dev/null
@@ -0,0 +1,159 @@
+;; Additional library functions for TinySCHEME.
+;;
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(macro (assert form)
+  `(if (not ,(cadr form))
+       (begin
+        (display (list "Assertion failed:" (quote ,(cadr form))))
+        (newline)
+        (exit 1))))
+(assert #t)
+
+(define (filter pred lst)
+  (cond ((null? lst) '())
+        ((pred (car lst))
+         (cons (car lst) (filter pred (cdr lst))))
+        (else (filter pred (cdr lst)))))
+
+(define (any p l)
+  (cond ((null? l) #f)
+        ((p (car l)) #t)
+        (else (any p (cdr l)))))
+
+(define (all p l)
+  (cond ((null? l) #t)
+        ((not (p (car l))) #f)
+        (else (all p (cdr l)))))
+
+;; Is PREFIX a prefix of S?
+(define (string-prefix? s prefix)
+  (and (>= (string-length s) (string-length prefix))
+       (string=? prefix (substring s 0 (string-length prefix)))))
+(assert (string-prefix? "Scheme" "Sch"))
+
+;; Is SUFFIX a suffix of S?
+(define (string-suffix? s suffix)
+  (and (>= (string-length s) (string-length suffix))
+       (string=? suffix (substring s (- (string-length s)
+                                       (string-length suffix))
+                                  (string-length s)))))
+(assert (string-suffix? "Scheme" "eme"))
+
+;; Locate the first occurrence of needle in haystack starting at offset.
+(ffi-define (string-index haystack needle [offset]))
+(assert (= 2 (string-index "Hallo" #\l)))
+(assert (= 3 (string-index "Hallo" #\l 3)))
+(assert (equal? #f (string-index "Hallo" #\.)))
+
+;; Locate the last occurrence of needle in haystack starting at offset.
+(ffi-define (string-rindex haystack needle [offset]))
+(assert (= 3 (string-rindex "Hallo" #\l)))
+(assert (equal? #f (string-rindex "Hallo" #\a 2)))
+(assert (equal? #f (string-rindex "Hallo" #\.)))
+
+;; Split haystack at delimiter at most n times.
+(define (string-splitn haystack delimiter n)
+  (let ((length (string-length haystack)))
+    (define (split acc delimiter offset n)
+      (if (>= offset length)
+         (reverse acc)
+         (let ((i (string-index haystack delimiter offset)))
+           (if (or (eq? i #f) (= 0 n))
+               (reverse (cons (substring haystack offset length) acc))
+               (split (cons (substring haystack offset i) acc)
+                      delimiter (+ i 1) (- n 1))))))
+    (split '() delimiter 0 n)))
+(assert (= 2 (length (string-splitn "foo:bar:baz" #\: 1))))
+(assert (string=? "foo" (car (string-splitn "foo:bar:baz" #\: 1))))
+(assert (string=? "bar:baz" (cadr (string-splitn "foo:bar:baz" #\: 1))))
+
+;; Split haystack at delimiter.
+(define (string-split haystack delimiter)
+  (string-splitn haystack delimiter -1))
+(assert (= 3 (length (string-split "foo:bar:baz" #\:))))
+(assert (string=? "foo" (car (string-split "foo:bar:baz" #\:))))
+(assert (string=? "bar" (cadr (string-split "foo:bar:baz" #\:))))
+(assert (string=? "baz" (caddr (string-split "foo:bar:baz" #\:))))
+
+;; Trim the prefix of S containing only characters that make PREDICATE
+;; true.
+(define (string-ltrim predicate s)
+  (let loop ((s' (string->list s)))
+    (if (predicate (car s'))
+       (loop (cdr s'))
+       (list->string s'))))
+(assert (string=? "foo" (string-ltrim char-whitespace? "  foo")))
+
+;; Trim the suffix of S containing only characters that make PREDICATE
+;; true.
+(define (string-rtrim predicate s)
+  (let loop ((s' (reverse (string->list s))))
+    (if (predicate (car s'))
+       (loop (cdr s'))
+       (list->string (reverse s')))))
+(assert (string=? "foo" (string-rtrim char-whitespace? "foo    ")))
+
+;; Trim both the prefix and suffix of S containing only characters
+;; that make PREDICATE true.
+(define (string-trim predicate s)
+  (string-ltrim predicate (string-rtrim predicate s)))
+(assert (string=? "foo" (string-trim char-whitespace? "        foo     ")))
+
+;; Check if needle is contained in haystack.
+(ffi-define (string-contains? haystack needle))
+(assert (string-contains? "Hallo" "llo"))
+(assert (not (string-contains? "Hallo" "olla")))
+
+;; Read a word from port P.
+(define (read-word . p)
+  (list->string
+   (let f ()
+     (let ((c (apply peek-char p)))
+       (cond
+       ((eof-object? c) '())
+       ((char-alphabetic? c)
+        (apply read-char p)
+        (cons c (f)))
+       (else
+        (apply read-char p)
+        '()))))))
+
+;; Read a line from port P.
+(define (read-line . p)
+  (list->string
+   (let f ()
+     (let ((c (apply peek-char p)))
+       (cond
+       ((eof-object? c) '())
+       ((char=? c #\newline)
+        (apply read-char p)
+        '())
+       (else
+        (apply read-char p)
+        (cons c (f))))))))
+
+;; Read everything from port P.
+(define (read-all . p)
+  (let loop ((acc (open-output-string)))
+    (let ((c (apply peek-char p)))
+      (cond
+       ((eof-object? c) (get-output-string acc))
+       (else
+       (write-char (apply read-char p) acc)
+       (loop acc))))))
diff --git a/tests/gpgscm/main.c b/tests/gpgscm/main.c
new file mode 100644 (file)
index 0000000..5b3792e
--- /dev/null
@@ -0,0 +1,288 @@
+/* TinyScheme-based test driver.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <gcrypt.h>
+#include <gpg-error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "private.h"
+#include "scheme.h"
+#include "ffi.h"
+#include "i18n.h"
+#include "../../common/argparse.h"
+#include "../../common/init.h"
+#include "../../common/logging.h"
+#include "../../common/strlist.h"
+#include "../../common/sysutils.h"
+#include "../../common/util.h"
+
+/* The TinyScheme banner.  Unfortunately, it isn't in the header
+   file.  */
+#define ts_banner "TinyScheme 1.41"
+
+int verbose;
+
+\f
+
+/* Constants to identify the commands and options. */
+enum cmd_and_opt_values
+  {
+    aNull      = 0,
+    oVerbose   = 'v',
+  };
+
+/* The list of commands and options. */
+static ARGPARSE_OPTS opts[] =
+  {
+    ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
+    ARGPARSE_end (),
+  };
+
+char *scmpath = "";
+size_t scmpath_len = 0;
+
+/* Command line parsing.  */
+static void
+parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
+{
+  int no_more_options = 0;
+
+  while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
+    {
+      switch (pargs->r_opt)
+        {
+        case oVerbose:
+          verbose++;
+          break;
+
+        default:
+         pargs->err = 2;
+         break;
+       }
+    }
+}
+
+/* Print usage information and and provide strings for help. */
+static const char *
+my_strusage( int level )
+{
+  const char *p;
+
+  switch (level)
+    {
+    case 11: p = "gpgscm (@GNUPG@)";
+      break;
+    case 13: p = VERSION; break;
+    case 17: p = PRINTABLE_OS_NAME; break;
+    case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
+
+    case 1:
+    case 40:
+      p = _("Usage: gpgscm [options] [file] (-h for help)");
+      break;
+    case 41:
+      p = _("Syntax: gpgscm [options] [file]\n"
+            "Execute the given Scheme program, or spawn interactive shell.\n");
+      break;
+
+    default: p = NULL; break;
+    }
+  return p;
+}
+
+\f
+/* Load the Scheme program from FILE_NAME.  If FILE_NAME is not an
+   absolute path, and LOOKUP_IN_PATH is given, then it is qualified
+   with the values in scmpath until the file is found.  */
+static gpg_error_t
+load (scheme *sc, char *file_name,
+      int lookup_in_cwd, int lookup_in_path)
+{
+  gpg_error_t err = 0;
+  size_t n;
+  const char *directory;
+  char *qualified_name = file_name;
+  int use_path;
+  FILE *h = NULL;
+
+  use_path =
+    lookup_in_path && ! (file_name[0] == '/' || scmpath_len == 0);
+
+  if (file_name[0] == '/' || lookup_in_cwd || scmpath_len == 0)
+    {
+      h = fopen (file_name, "r");
+      if (! h)
+        err = gpg_error_from_syserror ();
+    }
+
+  if (h == NULL && use_path)
+    for (directory = scmpath, n = scmpath_len; n;
+         directory += strlen (directory) + 1, n--)
+      {
+        if (asprintf (&qualified_name, "%s/%s", directory, file_name) < 0)
+          return gpg_error_from_syserror ();
+
+        h = fopen (qualified_name, "r");
+        if (h)
+          break;
+
+        if (n > 1)
+          {
+            free (qualified_name);
+            continue;  /* Try again!  */
+          }
+
+        err = gpg_error_from_syserror ();
+      }
+
+  if (h == NULL)
+    {
+      /* Failed and no more elements in scmpath to try.  */
+      fprintf (stderr, "Could not read %s: %s.\n",
+               qualified_name, gpg_strerror (err));
+      if (lookup_in_path)
+        fprintf (stderr,
+                 "Consider using GPGSCM_PATH to specify the location "
+                 "of the Scheme library.\n");
+      return err;
+    }
+  if (verbose > 1)
+    fprintf (stderr, "Loading %s...\n", qualified_name);
+  scheme_load_named_file (sc, h, qualified_name);
+  fclose (h);
+
+  if (file_name != qualified_name)
+    free (qualified_name);
+  return 0;
+}
+
+\f
+
+int
+main (int argc, char **argv)
+{
+  gpg_error_t err;
+  char *argv0;
+  ARGPARSE_ARGS pargs;
+  scheme *sc;
+  char *p;
+#if _WIN32
+  char pathsep = ';';
+#else
+  char pathsep = ':';
+#endif
+  char *script = NULL;
+
+  /* Save argv[0] so that we can re-exec.  */
+  argv0 = argv[0];
+
+  /* Parse path.  */
+  if (getenv ("GPGSCM_PATH"))
+    scmpath = getenv ("GPGSCM_PATH");
+
+  p = scmpath = strdup (scmpath);
+  if (p == NULL)
+    return 2;
+
+  if (*p)
+    scmpath_len++;
+  for (; *p; p++)
+    if (*p == pathsep)
+      *p = 0, scmpath_len++;
+
+  set_strusage (my_strusage);
+  log_set_prefix ("gpgscm", 1);
+
+  /* Make sure that our subsystems are ready.  */
+  i18n_init ();
+  init_common_subsystems (&argc, &argv);
+
+  if (!gcry_check_version (GCRYPT_VERSION))
+    {
+      fputs ("libgcrypt version mismatch\n", stderr);
+      exit (2);
+    }
+
+  /* Parse the command line. */
+  pargs.argc  = &argc;
+  pargs.argv  = &argv;
+  pargs.flags = 0;
+  parse_arguments (&pargs, opts);
+
+  if (log_get_errorcount (0))
+    exit (2);
+
+  sc = scheme_init_new_custom_alloc (gcry_malloc, gcry_free);
+  if (! sc) {
+    fprintf (stderr, "Could not initialize TinyScheme!\n");
+    return 2;
+  }
+  scheme_set_input_port_file (sc, stdin);
+  scheme_set_output_port_file (sc, stderr);
+
+  if (argc)
+    {
+      script = argv[0];
+      argc--, argv++;
+    }
+
+  err = load (sc, "init.scm", 0, 1);
+  if (! err)
+    err = load (sc, "ffi.scm", 0, 1);
+  if (! err)
+    err = ffi_init (sc, argv0, argc, (const char **) argv);
+  if (! err)
+    err = load (sc, "lib.scm", 0, 1);
+  if (! err)
+    err = load (sc, "repl.scm", 0, 1);
+  if (! err)
+    err = load (sc, "tests.scm", 0, 1);
+  if (err)
+    {
+      fprintf (stderr, "Error initializing gpgscm: %s.\n",
+               gpg_strerror (err));
+      exit (2);
+    }
+
+  if (script == NULL)
+    {
+      /* Interactive shell.  */
+      fprintf (stderr, "gpgscm/"ts_banner".\n");
+      scheme_load_string (sc, "(interactive-repl)");
+    }
+  else
+    {
+      err = load (sc, script, 1, 1);
+      if (err)
+        log_fatal ("%s: %s", script, gpg_strerror (err));
+    }
+
+  scheme_deinit (sc);
+  xfree (sc);
+  return EXIT_SUCCESS;
+}
diff --git a/tests/gpgscm/opdefines.h b/tests/gpgscm/opdefines.h
new file mode 100644 (file)
index 0000000..ceb4d0e
--- /dev/null
@@ -0,0 +1,195 @@
+    _OP_DEF(opexe_0, "load",                           1,  1,       TST_STRING,                      OP_LOAD             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_T0LVL            )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_T1LVL            )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_READ_INTERNAL    )
+    _OP_DEF(opexe_0, "gensym",                         0,  0,       0,                               OP_GENSYM           )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_VALUEPRINT       )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_EVAL             )
+#if USE_TRACING
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_REAL_EVAL        )
+#endif
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_E0ARGS           )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_E1ARGS           )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_APPLY            )
+#if USE_TRACING
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_REAL_APPLY       )
+    _OP_DEF(opexe_0, "tracing",                        1,  1,       TST_NATURAL,                     OP_TRACING          )
+#endif
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_DOMACRO          )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LAMBDA           )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LAMBDA1          )
+    _OP_DEF(opexe_0, "make-closure",                   1,  2,       TST_PAIR TST_ENVIRONMENT,        OP_MKCLOSURE        )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_QUOTE            )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_DEF0             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_DEF1             )
+    _OP_DEF(opexe_0, "defined?",                       1,  2,       TST_SYMBOL TST_ENVIRONMENT,      OP_DEFP             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_BEGIN            )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_IF0              )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_IF1              )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_SET0             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_SET1             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LET0             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LET1             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LET2             )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LET0AST          )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LET1AST          )
+    _OP_DEF(opexe_0, 0,                                0,  0,       0,                               OP_LET2AST          )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_LET0REC          )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_LET1REC          )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_LET2REC          )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_COND0            )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_COND1            )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_DELAY            )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_AND0             )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_AND1             )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_OR0              )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_OR1              )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_C0STREAM         )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_C1STREAM         )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_MACRO0           )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_MACRO1           )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_CASE0            )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_CASE1            )
+    _OP_DEF(opexe_1, 0,                                0,  0,       0,                               OP_CASE2            )
+    _OP_DEF(opexe_1, "eval",                           1,  2,       TST_ANY TST_ENVIRONMENT,         OP_PEVAL            )
+    _OP_DEF(opexe_1, "apply",                          1,  INF_ARG, TST_NONE,                        OP_PAPPLY           )
+    _OP_DEF(opexe_1, "call-with-current-continuation", 1,  1,       TST_NONE,                        OP_CONTINUATION     )
+#if USE_MATH
+    _OP_DEF(opexe_2, "inexact->exact",                 1,  1,       TST_NUMBER,                      OP_INEX2EX          )
+    _OP_DEF(opexe_2, "exp",                            1,  1,       TST_NUMBER,                      OP_EXP              )
+    _OP_DEF(opexe_2, "log",                            1,  1,       TST_NUMBER,                      OP_LOG              )
+    _OP_DEF(opexe_2, "sin",                            1,  1,       TST_NUMBER,                      OP_SIN              )
+    _OP_DEF(opexe_2, "cos",                            1,  1,       TST_NUMBER,                      OP_COS              )
+    _OP_DEF(opexe_2, "tan",                            1,  1,       TST_NUMBER,                      OP_TAN              )
+    _OP_DEF(opexe_2, "asin",                           1,  1,       TST_NUMBER,                      OP_ASIN             )
+    _OP_DEF(opexe_2, "acos",                           1,  1,       TST_NUMBER,                      OP_ACOS             )
+    _OP_DEF(opexe_2, "atan",                           1,  2,       TST_NUMBER,                      OP_ATAN             )
+    _OP_DEF(opexe_2, "sqrt",                           1,  1,       TST_NUMBER,                      OP_SQRT             )
+    _OP_DEF(opexe_2, "expt",                           2,  2,       TST_NUMBER,                      OP_EXPT             )
+    _OP_DEF(opexe_2, "floor",                          1,  1,       TST_NUMBER,                      OP_FLOOR            )
+    _OP_DEF(opexe_2, "ceiling",                        1,  1,       TST_NUMBER,                      OP_CEILING          )
+    _OP_DEF(opexe_2, "truncate",                       1,  1,       TST_NUMBER,                      OP_TRUNCATE         )
+    _OP_DEF(opexe_2, "round",                          1,  1,       TST_NUMBER,                      OP_ROUND            )
+#endif
+    _OP_DEF(opexe_2, "+",                              0,  INF_ARG, TST_NUMBER,                      OP_ADD              )
+    _OP_DEF(opexe_2, "-",                              1,  INF_ARG, TST_NUMBER,                      OP_SUB              )
+    _OP_DEF(opexe_2, "*",                              0,  INF_ARG, TST_NUMBER,                      OP_MUL              )
+    _OP_DEF(opexe_2, "/",                              1,  INF_ARG, TST_NUMBER,                      OP_DIV              )
+    _OP_DEF(opexe_2, "quotient",                       1,  INF_ARG, TST_INTEGER,                     OP_INTDIV           )
+    _OP_DEF(opexe_2, "remainder",                      2,  2,       TST_INTEGER,                     OP_REM              )
+    _OP_DEF(opexe_2, "modulo",                         2,  2,       TST_INTEGER,                     OP_MOD              )
+    _OP_DEF(opexe_2, "car",                            1,  1,       TST_PAIR,                        OP_CAR              )
+    _OP_DEF(opexe_2, "cdr",                            1,  1,       TST_PAIR,                        OP_CDR              )
+    _OP_DEF(opexe_2, "cons",                           2,  2,       TST_NONE,                        OP_CONS             )
+    _OP_DEF(opexe_2, "set-car!",                       2,  2,       TST_PAIR TST_ANY,                OP_SETCAR           )
+    _OP_DEF(opexe_2, "set-cdr!",                       2,  2,       TST_PAIR TST_ANY,                OP_SETCDR           )
+    _OP_DEF(opexe_2, "char->integer",                  1,  1,       TST_CHAR,                        OP_CHAR2INT         )
+    _OP_DEF(opexe_2, "integer->char",                  1,  1,       TST_NATURAL,                     OP_INT2CHAR         )
+    _OP_DEF(opexe_2, "char-upcase",                    1,  1,       TST_CHAR,                        OP_CHARUPCASE       )
+    _OP_DEF(opexe_2, "char-downcase",                  1,  1,       TST_CHAR,                        OP_CHARDNCASE       )
+    _OP_DEF(opexe_2, "symbol->string",                 1,  1,       TST_SYMBOL,                      OP_SYM2STR          )
+    _OP_DEF(opexe_2, "atom->string",                   1,  2,       TST_ANY TST_NATURAL,             OP_ATOM2STR         )
+    _OP_DEF(opexe_2, "string->symbol",                 1,  1,       TST_STRING,                      OP_STR2SYM          )
+    _OP_DEF(opexe_2, "string->atom",                   1,  2,       TST_STRING TST_NATURAL,          OP_STR2ATOM         )
+    _OP_DEF(opexe_2, "make-string",                    1,  2,       TST_NATURAL TST_CHAR,            OP_MKSTRING         )
+    _OP_DEF(opexe_2, "string-length",                  1,  1,       TST_STRING,                      OP_STRLEN           )
+    _OP_DEF(opexe_2, "string-ref",                     2,  2,       TST_STRING TST_NATURAL,          OP_STRREF           )
+    _OP_DEF(opexe_2, "string-set!",                    3,  3,       TST_STRING TST_NATURAL TST_CHAR, OP_STRSET           )
+    _OP_DEF(opexe_2, "string-append",                  0,  INF_ARG, TST_STRING,                      OP_STRAPPEND        )
+    _OP_DEF(opexe_2, "substring",                      2,  3,       TST_STRING TST_NATURAL,          OP_SUBSTR           )
+    _OP_DEF(opexe_2, "vector",                         0,  INF_ARG, TST_NONE,                        OP_VECTOR           )
+    _OP_DEF(opexe_2, "make-vector",                    1,  2,       TST_NATURAL TST_ANY,             OP_MKVECTOR         )
+    _OP_DEF(opexe_2, "vector-length",                  1,  1,       TST_VECTOR,                      OP_VECLEN           )
+    _OP_DEF(opexe_2, "vector-ref",                     2,  2,       TST_VECTOR TST_NATURAL,          OP_VECREF           )
+    _OP_DEF(opexe_2, "vector-set!",                    3,  3,       TST_VECTOR TST_NATURAL TST_ANY,  OP_VECSET           )
+    _OP_DEF(opexe_3, "not",                            1,  1,       TST_NONE,                        OP_NOT              )
+    _OP_DEF(opexe_3, "boolean?",                       1,  1,       TST_NONE,                        OP_BOOLP            )
+    _OP_DEF(opexe_3, "eof-object?",                    1,  1,       TST_NONE,                        OP_EOFOBJP          )
+    _OP_DEF(opexe_3, "null?",                          1,  1,       TST_NONE,                        OP_NULLP            )
+    _OP_DEF(opexe_3, "=",                              2,  INF_ARG, TST_NUMBER,                      OP_NUMEQ            )
+    _OP_DEF(opexe_3, "<",                              2,  INF_ARG, TST_NUMBER,                      OP_LESS             )
+    _OP_DEF(opexe_3, ">",                              2,  INF_ARG, TST_NUMBER,                      OP_GRE              )
+    _OP_DEF(opexe_3, "<=",                             2,  INF_ARG, TST_NUMBER,                      OP_LEQ              )
+    _OP_DEF(opexe_3, ">=",                             2,  INF_ARG, TST_NUMBER,                      OP_GEQ              )
+    _OP_DEF(opexe_3, "symbol?",                        1,  1,       TST_ANY,                         OP_SYMBOLP          )
+    _OP_DEF(opexe_3, "number?",                        1,  1,       TST_ANY,                         OP_NUMBERP          )
+    _OP_DEF(opexe_3, "string?",                        1,  1,       TST_ANY,                         OP_STRINGP          )
+    _OP_DEF(opexe_3, "integer?",                       1,  1,       TST_ANY,                         OP_INTEGERP         )
+    _OP_DEF(opexe_3, "real?",                          1,  1,       TST_ANY,                         OP_REALP            )
+    _OP_DEF(opexe_3, "char?",                          1,  1,       TST_ANY,                         OP_CHARP            )
+#if USE_CHAR_CLASSIFIERS
+    _OP_DEF(opexe_3, "char-alphabetic?",               1,  1,       TST_CHAR,                        OP_CHARAP           )
+    _OP_DEF(opexe_3, "char-numeric?",                  1,  1,       TST_CHAR,                        OP_CHARNP           )
+    _OP_DEF(opexe_3, "char-whitespace?",               1,  1,       TST_CHAR,                        OP_CHARWP           )
+    _OP_DEF(opexe_3, "char-upper-case?",               1,  1,       TST_CHAR,                        OP_CHARUP           )
+    _OP_DEF(opexe_3, "char-lower-case?",               1,  1,       TST_CHAR,                        OP_CHARLP           )
+#endif
+    _OP_DEF(opexe_3, "port?",                          1,  1,       TST_ANY,                         OP_PORTP            )
+    _OP_DEF(opexe_3, "input-port?",                    1,  1,       TST_ANY,                         OP_INPORTP          )
+    _OP_DEF(opexe_3, "output-port?",                   1,  1,       TST_ANY,                         OP_OUTPORTP         )
+    _OP_DEF(opexe_3, "procedure?",                     1,  1,       TST_ANY,                         OP_PROCP            )
+    _OP_DEF(opexe_3, "pair?",                          1,  1,       TST_ANY,                         OP_PAIRP            )
+    _OP_DEF(opexe_3, "list?",                          1,  1,       TST_ANY,                         OP_LISTP            )
+    _OP_DEF(opexe_3, "environment?",                   1,  1,       TST_ANY,                         OP_ENVP             )
+    _OP_DEF(opexe_3, "vector?",                        1,  1,       TST_ANY,                         OP_VECTORP          )
+    _OP_DEF(opexe_3, "eq?",                            2,  2,       TST_ANY,                         OP_EQ               )
+    _OP_DEF(opexe_3, "eqv?",                           2,  2,       TST_ANY,                         OP_EQV              )
+    _OP_DEF(opexe_4, "force",                          1,  1,       TST_ANY,                         OP_FORCE            )
+    _OP_DEF(opexe_4, 0,                                0,  0,       0,                               OP_SAVE_FORCED      )
+    _OP_DEF(opexe_4, "write",                          1,  2,       TST_ANY TST_OUTPORT,             OP_WRITE            )
+    _OP_DEF(opexe_4, "write-char",                     1,  2,       TST_CHAR TST_OUTPORT,            OP_WRITE_CHAR       )
+    _OP_DEF(opexe_4, "display",                        1,  2,       TST_ANY TST_OUTPORT,             OP_DISPLAY          )
+    _OP_DEF(opexe_4, "newline",                        0,  1,       TST_OUTPORT,                     OP_NEWLINE          )
+    _OP_DEF(opexe_4, "error",                          1,  INF_ARG, TST_NONE,                        OP_ERR0             )
+    _OP_DEF(opexe_4, 0,                                0,  0,       0,                               OP_ERR1             )
+    _OP_DEF(opexe_4, "reverse",                        1,  1,       TST_LIST,                        OP_REVERSE          )
+    _OP_DEF(opexe_4, "list*",                          1,  INF_ARG, TST_NONE,                        OP_LIST_STAR        )
+    _OP_DEF(opexe_4, "append",                         0,  INF_ARG, TST_NONE,                        OP_APPEND           )
+#if USE_PLIST
+    _OP_DEF(opexe_4, "put",                            3,  3,       TST_NONE,                        OP_PUT              )
+    _OP_DEF(opexe_4, "get",                            2,  2,       TST_NONE,                        OP_GET              )
+#endif
+    _OP_DEF(opexe_4, "quit",                           0,  1,       TST_NUMBER,                      OP_QUIT             )
+    _OP_DEF(opexe_4, "gc",                             0,  0,       0,                               OP_GC               )
+    _OP_DEF(opexe_4, "gc-verbose",                     0,  1,       TST_NONE,                        OP_GCVERB           )
+    _OP_DEF(opexe_4, "new-segment",                    0,  1,       TST_NUMBER,                      OP_NEWSEGMENT       )
+    _OP_DEF(opexe_4, "oblist",                         0,  0,       0,                               OP_OBLIST           )
+    _OP_DEF(opexe_4, "current-input-port",             0,  0,       0,                               OP_CURR_INPORT      )
+    _OP_DEF(opexe_4, "current-output-port",            0,  0,       0,                               OP_CURR_OUTPORT     )
+    _OP_DEF(opexe_4, "open-input-file",                1,  1,       TST_STRING,                      OP_OPEN_INFILE      )
+    _OP_DEF(opexe_4, "open-output-file",               1,  1,       TST_STRING,                      OP_OPEN_OUTFILE     )
+    _OP_DEF(opexe_4, "open-input-output-file",         1,  1,       TST_STRING,                      OP_OPEN_INOUTFILE   )
+#if USE_STRING_PORTS
+    _OP_DEF(opexe_4, "open-input-string",              1,  1,       TST_STRING,                      OP_OPEN_INSTRING    )
+    _OP_DEF(opexe_4, "open-input-output-string",       1,  1,       TST_STRING,                      OP_OPEN_INOUTSTRING )
+    _OP_DEF(opexe_4, "open-output-string",             0,  1,       TST_STRING,                      OP_OPEN_OUTSTRING   )
+    _OP_DEF(opexe_4, "get-output-string",              1,  1,       TST_OUTPORT,                     OP_GET_OUTSTRING    )
+#endif
+    _OP_DEF(opexe_4, "close-input-port",               1,  1,       TST_INPORT,                      OP_CLOSE_INPORT     )
+    _OP_DEF(opexe_4, "close-output-port",              1,  1,       TST_OUTPORT,                     OP_CLOSE_OUTPORT    )
+    _OP_DEF(opexe_4, "interaction-environment",        0,  0,       0,                               OP_INT_ENV          )
+    _OP_DEF(opexe_4, "current-environment",            0,  0,       0,                               OP_CURR_ENV         )
+    _OP_DEF(opexe_5, "read",                           0,  1,       TST_INPORT,                      OP_READ             )
+    _OP_DEF(opexe_5, "read-char",                      0,  1,       TST_INPORT,                      OP_READ_CHAR        )
+    _OP_DEF(opexe_5, "peek-char",                      0,  1,       TST_INPORT,                      OP_PEEK_CHAR        )
+    _OP_DEF(opexe_5, "char-ready?",                    0,  1,       TST_INPORT,                      OP_CHAR_READY       )
+    _OP_DEF(opexe_5, "set-input-port",                 1,  1,       TST_INPORT,                      OP_SET_INPORT       )
+    _OP_DEF(opexe_5, "set-output-port",                1,  1,       TST_OUTPORT,                     OP_SET_OUTPORT      )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDSEXPR          )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDLIST           )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDDOT            )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDQUOTE          )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDQQUOTE         )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDQQUOTEVEC      )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDUNQUOTE        )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDUQTSP          )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_RDVEC            )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_P0LIST           )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_P1LIST           )
+    _OP_DEF(opexe_5, 0,                                0,  0,       0,                               OP_PVECFROM         )
+    _OP_DEF(opexe_6, "length",                         1,  1,       TST_LIST,                        OP_LIST_LENGTH      )
+    _OP_DEF(opexe_6, "assq",                           2,  2,       TST_NONE,                        OP_ASSQ             )
+    _OP_DEF(opexe_6, "get-closure-code",               1,  1,       TST_NONE,                        OP_GET_CLOSURE      )
+    _OP_DEF(opexe_6, "closure?",                       1,  1,       TST_NONE,                        OP_CLOSUREP         )
+    _OP_DEF(opexe_6, "macro?",                         1,  1,       TST_NONE,                        OP_MACROP           )
+#undef _OP_DEF
diff --git a/tests/gpgscm/private.h b/tests/gpgscm/private.h
new file mode 100644 (file)
index 0000000..efa0cb0
--- /dev/null
@@ -0,0 +1,26 @@
+/* TinyScheme-based test driver.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GPGSCM_PRIVATE_H__
+#define __GPGSCM_PRIVATE_H__
+
+extern int verbose;
+
+#endif /* __GPGSCM_PRIVATE_H__ */
diff --git a/tests/gpgscm/repl.scm b/tests/gpgscm/repl.scm
new file mode 100644 (file)
index 0000000..896554f
--- /dev/null
@@ -0,0 +1,50 @@
+;; A read-evaluate-print-loop for gpgscm.
+;;
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+;; Interactive repl using 'prompt' function.  P must be a function
+;; that given the current entered prefix returns the prompt to
+;; display.
+(define (repl p)
+  (let ((repl-environment (make-environment)))
+    (call/cc
+     (lambda (exit)
+       (let loop ((prefix ""))
+        (let ((line (prompt (p prefix))))
+          (if (and (not (eof-object? line)) (= 0 (string-length line)))
+              (exit (loop prefix)))
+          (if (not (eof-object? line))
+              (let* ((next (string-append prefix line))
+                     (c (catch (begin (echo "Parse error:" *error*)
+                                      (loop prefix))
+                               (read (open-input-string next)))))
+                (if (not (eof-object? c))
+                    (begin
+                      (catch (echo "Error:" *error*)
+                             (echo "    ===>" (eval c repl-environment)))
+                      (exit (loop ""))))
+                (exit (loop next))))))))))
+
+(define (prompt-append-prefix prompt prefix)
+  (string-append prompt (if (> (string-length prefix) 0)
+                           (string-append prefix "...")
+                           "> ")))
+
+;; Default repl run by main.c.
+(define (interactive-repl)
+  (repl (lambda (p) (prompt-append-prefix "gpgscm " p))))
diff --git a/tests/gpgscm/scheme-config.h b/tests/gpgscm/scheme-config.h
new file mode 100644 (file)
index 0000000..fe3d746
--- /dev/null
@@ -0,0 +1,36 @@
+/* TinyScheme configuration.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define STANDALONE             0
+#define USE_MATH               0
+#define USE_CHAR_CLASSIFIERS   1
+#define USE_ASCII_NAMES                1
+#define USE_STRING_PORTS       1
+#define USE_ERROR_HOOK         1
+#define USE_TRACING            1
+#define USE_COLON_HOOK         1
+#define USE_DL                 0
+#define USE_PLIST              0
+#define USE_INTERFACE          1
+#define SHOW_ERROR_LINE                1
+
+#if __MINGW32__
+# define USE_STRLWR 0
+#endif /* __MINGW32__ */
diff --git a/tests/gpgscm/scheme-private.h b/tests/gpgscm/scheme-private.h
new file mode 100644 (file)
index 0000000..9eafe76
--- /dev/null
@@ -0,0 +1,228 @@
+/* scheme-private.h */
+
+#ifndef _SCHEME_PRIVATE_H
+#define _SCHEME_PRIVATE_H
+
+#include "scheme.h"
+/*------------------ Ugly internals -----------------------------------*/
+/*------------------ Of interest only to FFI users --------------------*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum scheme_port_kind {
+  port_free=0,
+  port_file=1,
+  port_string=2,
+  port_srfi6=4,
+  port_input=16,
+  port_output=32,
+  port_saw_EOF=64
+};
+
+typedef struct port {
+  unsigned char kind;
+  union {
+    struct {
+      FILE *file;
+      int closeit;
+#if SHOW_ERROR_LINE
+      int curr_line;
+      char *filename;
+#endif
+    } stdio;
+    struct {
+      char *start;
+      char *past_the_end;
+      char *curr;
+    } string;
+  } rep;
+} port;
+
+/* cell structure */
+struct cell {
+  unsigned int _flag;
+  union {
+    struct {
+      char   *_svalue;
+      int   _length;
+    } _string;
+    num _number;
+    port *_port;
+    foreign_func _ff;
+    struct {
+      struct cell *_car;
+      struct cell *_cdr;
+    } _cons;
+    struct {
+         char *_data;
+         const foreign_object_vtable *_vtable;
+    } _foreign_object;
+  } _object;
+};
+
+struct scheme {
+/* arrays for segments */
+func_alloc malloc;
+func_dealloc free;
+
+/* return code */
+int retcode;
+int tracing;
+
+
+#ifndef CELL_SEGSIZE
+#define CELL_SEGSIZE    5000  /* # of cells in one segment */
+#endif
+#ifndef CELL_NSEGMENT
+#define CELL_NSEGMENT   10    /* # of segments for cells */
+#endif
+char *alloc_seg[CELL_NSEGMENT];
+pointer cell_seg[CELL_NSEGMENT];
+int     last_cell_seg;
+
+/* We use 4 registers. */
+pointer args;            /* register for arguments of function */
+pointer envir;           /* stack register for current environment */
+pointer code;            /* register for current code */
+pointer dump;            /* stack register for next evaluation */
+
+int interactive_repl;    /* are we in an interactive REPL? */
+
+struct cell _sink;
+pointer sink;            /* when mem. alloc. fails */
+struct cell _NIL;
+pointer NIL;             /* special cell representing empty cell */
+struct cell _HASHT;
+pointer T;               /* special cell representing #t */
+struct cell _HASHF;
+pointer F;               /* special cell representing #f */
+struct cell _EOF_OBJ;
+pointer EOF_OBJ;         /* special cell representing end-of-file object */
+pointer oblist;          /* pointer to symbol table */
+pointer global_env;      /* pointer to global environment */
+pointer c_nest;          /* stack for nested calls from C */
+
+/* global pointers to special symbols */
+pointer LAMBDA;               /* pointer to syntax lambda */
+pointer QUOTE;           /* pointer to syntax quote */
+
+pointer QQUOTE;               /* pointer to symbol quasiquote */
+pointer UNQUOTE;         /* pointer to symbol unquote */
+pointer UNQUOTESP;       /* pointer to symbol unquote-splicing */
+pointer FEED_TO;         /* => */
+pointer COLON_HOOK;      /* *colon-hook* */
+pointer ERROR_HOOK;      /* *error-hook* */
+pointer SHARP_HOOK;  /* *sharp-hook* */
+pointer COMPILE_HOOK;  /* *compile-hook* */
+
+pointer free_cell;       /* pointer to top of free cells */
+long    fcells;          /* # of free cells */
+
+pointer inport;
+pointer outport;
+pointer save_inport;
+pointer loadport;
+
+#ifndef MAXFIL
+#define MAXFIL 64
+#endif
+port load_stack[MAXFIL];     /* Stack of open files for port -1 (LOADing) */
+int nesting_stack[MAXFIL];
+int file_i;
+int nesting;
+
+char    gc_verbose;      /* if gc_verbose is not zero, print gc status */
+char    no_memory;       /* Whether mem. alloc. has failed */
+
+#ifndef LINESIZE
+#define LINESIZE 1024
+#endif
+char    linebuff[LINESIZE];
+#ifndef STRBUFFSIZE
+#define STRBUFFSIZE 256
+#endif
+char    *strbuff;
+size_t strbuff_size;
+FILE *tmpfp;
+int tok;
+int print_flag;
+pointer value;
+int op;
+
+void *ext_data;     /* For the benefit of foreign functions */
+long gensym_cnt;
+
+struct scheme_interface *vptr;
+void *dump_base;    /* pointer to base of allocated dump stack */
+int dump_size;      /* number of frames allocated for dump stack */
+};
+
+/* operator code */
+enum scheme_opcodes {
+#define _OP_DEF(A,B,C,D,E,OP) OP,
+#include "opdefines.h"
+  OP_MAXDEFINED
+};
+
+
+#define cons(sc,a,b) _cons(sc,a,b,0)
+#define immutable_cons(sc,a,b) _cons(sc,a,b,1)
+
+int is_string(pointer p);
+char *string_value(pointer p);
+int is_number(pointer p);
+num nvalue(pointer p);
+long ivalue(pointer p);
+double rvalue(pointer p);
+int is_integer(pointer p);
+int is_real(pointer p);
+int is_character(pointer p);
+long charvalue(pointer p);
+int is_vector(pointer p);
+
+int is_port(pointer p);
+
+int is_pair(pointer p);
+pointer pair_car(pointer p);
+pointer pair_cdr(pointer p);
+pointer set_car(pointer p, pointer q);
+pointer set_cdr(pointer p, pointer q);
+
+int is_symbol(pointer p);
+char *symname(pointer p);
+int hasprop(pointer p);
+
+int is_syntax(pointer p);
+int is_proc(pointer p);
+int is_foreign(pointer p);
+char *syntaxname(pointer p);
+int is_closure(pointer p);
+#ifdef USE_MACRO
+int is_macro(pointer p);
+#endif
+pointer closure_code(pointer p);
+pointer closure_env(pointer p);
+
+int is_continuation(pointer p);
+int is_promise(pointer p);
+int is_environment(pointer p);
+int is_immutable(pointer p);
+void setimmutable(pointer p);
+
+int is_foreign_object(pointer p);
+const foreign_object_vtable *get_foreign_object_vtable(pointer p);
+void *get_foreign_object_data(pointer p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*
+Local variables:
+c-file-style: "k&r"
+End:
+*/
diff --git a/tests/gpgscm/scheme.c b/tests/gpgscm/scheme.c
new file mode 100644 (file)
index 0000000..0a76205
--- /dev/null
@@ -0,0 +1,5169 @@
+/* T I N Y S C H E M E    1 . 4 1
+ *   Dimitrios Souflis (dsouflis@acm.org)
+ *   Based on MiniScheme (original credits follow)
+ * (MINISCM)               coded by Atsushi Moriwaki (11/5/1989)
+ * (MINISCM)           E-MAIL :  moriwaki@kurims.kurims.kyoto-u.ac.jp
+ * (MINISCM) This version has been modified by R.C. Secrist.
+ * (MINISCM)
+ * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
+ * (MINISCM)
+ * (MINISCM) This is a revised and modified version by Akira KIDA.
+ * (MINISCM)    current version is 0.85k4 (15 May 1994)
+ *
+ */
+
+#define _SCHEME_SOURCE
+#include "scheme-private.h"
+#ifndef WIN32
+# include <unistd.h>
+#endif
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+#if USE_DL
+# include "dynload.h"
+#endif
+#if USE_MATH
+# include <math.h>
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <float.h>
+#include <ctype.h>
+
+#if USE_STRCASECMP
+#include <strings.h>
+# ifndef __APPLE__
+#  define stricmp strcasecmp
+# endif
+#endif
+
+/* Used for documentation purposes, to signal functions in 'interface' */
+#define INTERFACE
+
+#define TOK_EOF     (-1)
+#define TOK_LPAREN  0
+#define TOK_RPAREN  1
+#define TOK_DOT     2
+#define TOK_ATOM    3
+#define TOK_QUOTE   4
+#define TOK_COMMENT 5
+#define TOK_DQUOTE  6
+#define TOK_BQUOTE  7
+#define TOK_COMMA   8
+#define TOK_ATMARK  9
+#define TOK_SHARP   10
+#define TOK_SHARP_CONST 11
+#define TOK_VEC     12
+
+#define BACKQUOTE '`'
+#define DELIMITERS  "()\";\f\t\v\n\r "
+
+/*
+ *  Basic memory allocation units
+ */
+
+#define banner "TinyScheme 1.41"
+
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifdef __APPLE__
+static int stricmp(const char *s1, const char *s2)
+{
+  unsigned char c1, c2;
+  do {
+    c1 = tolower(*s1);
+    c2 = tolower(*s2);
+    if (c1 < c2)
+      return -1;
+    else if (c1 > c2)
+      return 1;
+    s1++, s2++;
+  } while (c1 != 0);
+  return 0;
+}
+#endif /* __APPLE__ */
+
+#if USE_STRLWR
+static const char *strlwr(char *s) {
+  const char *p=s;
+  while(*s) {
+    *s=tolower(*s);
+    s++;
+  }
+  return p;
+}
+#endif
+
+#ifndef prompt
+# define prompt "ts> "
+#endif
+
+#ifndef InitFile
+# define InitFile "init.scm"
+#endif
+
+#ifndef FIRST_CELLSEGS
+# define FIRST_CELLSEGS 3
+#endif
+
+enum scheme_types {
+  T_STRING=1,
+  T_NUMBER=2,
+  T_SYMBOL=3,
+  T_PROC=4,
+  T_PAIR=5,
+  T_CLOSURE=6,
+  T_CONTINUATION=7,
+  T_FOREIGN=8,
+  T_CHARACTER=9,
+  T_PORT=10,
+  T_VECTOR=11,
+  T_MACRO=12,
+  T_PROMISE=13,
+  T_ENVIRONMENT=14,
+  T_FOREIGN_OBJECT=15,
+  T_BOOLEAN=16,
+  T_NIL=17,
+  T_EOF_OBJ=18,
+  T_SINK=19,
+  T_LAST_SYSTEM_TYPE=19
+};
+
+static const char *
+type_to_string (enum scheme_types typ)
+{
+     switch (typ)
+     {
+     case T_STRING: return "string";
+     case T_NUMBER: return "number";
+     case T_SYMBOL: return "symbol";
+     case T_PROC: return "proc";
+     case T_PAIR: return "pair";
+     case T_CLOSURE: return "closure";
+     case T_CONTINUATION: return "configuration";
+     case T_FOREIGN: return "foreign";
+     case T_CHARACTER: return "character";
+     case T_PORT: return "port";
+     case T_VECTOR: return "vector";
+     case T_MACRO: return "macro";
+     case T_PROMISE: return "promise";
+     case T_ENVIRONMENT: return "environment";
+     case T_FOREIGN_OBJECT: return "foreign object";
+     case T_BOOLEAN: return "boolean";
+     case T_NIL: return "nil";
+     case T_EOF_OBJ: return "eof object";
+     case T_SINK: return "sink";
+     }
+     assert (! "not reached");
+}
+
+/* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
+#define ADJ 32
+#define TYPE_BITS 5
+#define T_MASKTYPE      31    /* 0000000000011111 */
+#define T_SYNTAX      4096    /* 0001000000000000 */
+#define T_IMMUTABLE   8192    /* 0010000000000000 */
+#define T_ATOM       16384    /* 0100000000000000 */   /* only for gc */
+#define CLRATOM      49151    /* 1011111111111111 */   /* only for gc */
+#define MARK         32768    /* 1000000000000000 */
+#define UNMARK       32767    /* 0111111111111111 */
+
+
+static num num_add(num a, num b);
+static num num_mul(num a, num b);
+static num num_div(num a, num b);
+static num num_intdiv(num a, num b);
+static num num_sub(num a, num b);
+static num num_rem(num a, num b);
+static num num_mod(num a, num b);
+static int num_eq(num a, num b);
+static int num_gt(num a, num b);
+static int num_ge(num a, num b);
+static int num_lt(num a, num b);
+static int num_le(num a, num b);
+
+#if USE_MATH
+static double round_per_R5RS(double x);
+#endif
+static int is_zero_double(double x);
+static INLINE int num_is_integer(pointer p) {
+  return ((p)->_object._number.is_fixnum);
+}
+
+static num num_zero;
+static num num_one;
+
+/* macros for cell operations */
+#define typeflag(p)      ((p)->_flag)
+#define type(p)          (typeflag(p)&T_MASKTYPE)
+
+INTERFACE INLINE int is_string(pointer p)     { return (type(p)==T_STRING); }
+#define strvalue(p)      ((p)->_object._string._svalue)
+#define strlength(p)        ((p)->_object._string._length)
+
+INTERFACE static int is_list(scheme *sc, pointer p);
+INTERFACE INLINE int is_vector(pointer p)    { return (type(p)==T_VECTOR); }
+INTERFACE static void fill_vector(pointer vec, pointer obj);
+INTERFACE static pointer vector_elem(pointer vec, int ielem);
+INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
+INTERFACE INLINE int is_number(pointer p)    { return (type(p)==T_NUMBER); }
+INTERFACE INLINE int is_integer(pointer p) {
+  if (!is_number(p))
+      return 0;
+  if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
+      return 1;
+  return 0;
+}
+
+INTERFACE INLINE int is_real(pointer p) {
+  return is_number(p) && (!(p)->_object._number.is_fixnum);
+}
+
+INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
+INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
+INLINE num nvalue(pointer p)       { return ((p)->_object._number); }
+INTERFACE long ivalue(pointer p)      { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
+INTERFACE double rvalue(pointer p)    { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
+#define ivalue_unchecked(p)       ((p)->_object._number.value.ivalue)
+#define rvalue_unchecked(p)       ((p)->_object._number.value.rvalue)
+#define set_num_integer(p)   (p)->_object._number.is_fixnum=1;
+#define set_num_real(p)      (p)->_object._number.is_fixnum=0;
+INTERFACE  long charvalue(pointer p)  { return ivalue_unchecked(p); }
+
+INTERFACE INLINE int is_port(pointer p)     { return (type(p)==T_PORT); }
+INTERFACE INLINE int is_inport(pointer p)  { return is_port(p) && p->_object._port->kind & port_input; }
+INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
+
+INTERFACE INLINE int is_pair(pointer p)     { return (type(p)==T_PAIR); }
+#define car(p)           ((p)->_object._cons._car)
+#define cdr(p)           ((p)->_object._cons._cdr)
+INTERFACE pointer pair_car(pointer p)   { return car(p); }
+INTERFACE pointer pair_cdr(pointer p)   { return cdr(p); }
+INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
+INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
+
+INTERFACE INLINE int is_symbol(pointer p)   { return (type(p)==T_SYMBOL); }
+INTERFACE INLINE char *symname(pointer p)   { return strvalue(car(p)); }
+#if USE_PLIST
+SCHEME_EXPORT INLINE int hasprop(pointer p)     { return (typeflag(p)&T_SYMBOL); }
+#define symprop(p)       cdr(p)
+#endif
+
+INTERFACE INLINE int is_syntax(pointer p)   { return (typeflag(p)&T_SYNTAX); }
+INTERFACE INLINE int is_proc(pointer p)     { return (type(p)==T_PROC); }
+INTERFACE INLINE int is_foreign(pointer p)  { return (type(p)==T_FOREIGN); }
+INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
+#define procnum(p)       ivalue(p)
+static const char *procname(pointer x);
+
+INTERFACE INLINE int is_closure(pointer p)  { return (type(p)==T_CLOSURE); }
+INTERFACE INLINE int is_macro(pointer p)    { return (type(p)==T_MACRO); }
+INTERFACE INLINE pointer closure_code(pointer p)   { return car(p); }
+INTERFACE INLINE pointer closure_env(pointer p)    { return cdr(p); }
+
+INTERFACE INLINE int is_continuation(pointer p)    { return (type(p)==T_CONTINUATION); }
+#define cont_dump(p)     cdr(p)
+
+INTERFACE INLINE int is_foreign_object(pointer p) { return (type(p)==T_FOREIGN_OBJECT); }
+INTERFACE const foreign_object_vtable *get_foreign_object_vtable(pointer p) {
+  return p->_object._foreign_object._vtable;
+}
+INTERFACE void *get_foreign_object_data(pointer p) {
+  return p->_object._foreign_object._data;
+}
+
+/* To do: promise should be forced ONCE only */
+INTERFACE INLINE int is_promise(pointer p)  { return (type(p)==T_PROMISE); }
+
+INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
+#define setenvironment(p)    typeflag(p) = T_ENVIRONMENT
+
+#define is_atom(p)       (typeflag(p)&T_ATOM)
+#define setatom(p)       typeflag(p) |= T_ATOM
+#define clratom(p)       typeflag(p) &= CLRATOM
+
+#define is_mark(p)       (typeflag(p)&MARK)
+#define setmark(p)       typeflag(p) |= MARK
+#define clrmark(p)       typeflag(p) &= UNMARK
+
+INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
+/*#define setimmutable(p)  typeflag(p) |= T_IMMUTABLE*/
+INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
+
+#define caar(p)          car(car(p))
+#define cadr(p)          car(cdr(p))
+#define cdar(p)          cdr(car(p))
+#define cddr(p)          cdr(cdr(p))
+#define cadar(p)         car(cdr(car(p)))
+#define caddr(p)         car(cdr(cdr(p)))
+#define cdaar(p)         cdr(car(car(p)))
+#define cadaar(p)        car(cdr(car(car(p))))
+#define cadddr(p)        car(cdr(cdr(cdr(p))))
+#define cddddr(p)        cdr(cdr(cdr(cdr(p))))
+
+#if USE_CHAR_CLASSIFIERS
+static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
+static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
+static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
+static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
+static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
+#endif
+
+#if USE_ASCII_NAMES
+static const char *charnames[32]={
+ "nul",
+ "soh",
+ "stx",
+ "etx",
+ "eot",
+ "enq",
+ "ack",
+ "bel",
+ "bs",
+ "ht",
+ "lf",
+ "vt",
+ "ff",
+ "cr",
+ "so",
+ "si",
+ "dle",
+ "dc1",
+ "dc2",
+ "dc3",
+ "dc4",
+ "nak",
+ "syn",
+ "etb",
+ "can",
+ "em",
+ "sub",
+ "esc",
+ "fs",
+ "gs",
+ "rs",
+ "us"
+};
+
+static int is_ascii_name(const char *name, int *pc) {
+  int i;
+  for(i=0; i<32; i++) {
+     if(stricmp(name,charnames[i])==0) {
+          *pc=i;
+          return 1;
+     }
+  }
+  if(stricmp(name,"del")==0) {
+     *pc=127;
+     return 1;
+  }
+  return 0;
+}
+
+#endif
+
+static int file_push(scheme *sc, const char *fname);
+static void file_pop(scheme *sc);
+static int file_interactive(scheme *sc);
+static INLINE int is_one_of(char *s, int c);
+static int alloc_cellseg(scheme *sc, int n);
+static long binary_decode(const char *s);
+static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
+static pointer _get_cell(scheme *sc, pointer a, pointer b);
+static pointer reserve_cells(scheme *sc, int n);
+static pointer get_consecutive_cells(scheme *sc, int n);
+static pointer find_consecutive_cells(scheme *sc, int n);
+static void finalize_cell(scheme *sc, pointer a);
+static int count_consecutive_cells(pointer x, int needed);
+static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
+static pointer mk_number(scheme *sc, num n);
+static char *store_string(scheme *sc, int len, const char *str, char fill);
+static pointer mk_vector(scheme *sc, int len);
+static pointer mk_atom(scheme *sc, char *q);
+static pointer mk_sharp_const(scheme *sc, char *name);
+static pointer mk_port(scheme *sc, port *p);
+static pointer port_from_filename(scheme *sc, const char *fn, int prop);
+static pointer port_from_file(scheme *sc, FILE *, int prop);
+static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
+static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
+static port *port_rep_from_file(scheme *sc, FILE *, int prop);
+static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
+static void port_close(scheme *sc, pointer p, int flag);
+static void mark(pointer a);
+static void gc(scheme *sc, pointer a, pointer b);
+static int basic_inchar(port *pt);
+static int inchar(scheme *sc);
+static void backchar(scheme *sc, int c);
+static char   *readstr_upto(scheme *sc, char *delim);
+static pointer readstrexp(scheme *sc);
+static INLINE int skipspace(scheme *sc);
+static int token(scheme *sc);
+static void printslashstring(scheme *sc, char *s, int len);
+static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
+static void printatom(scheme *sc, pointer l, int f);
+static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
+static pointer mk_closure(scheme *sc, pointer c, pointer e);
+static pointer mk_continuation(scheme *sc, pointer d);
+static pointer reverse(scheme *sc, pointer a);
+static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
+static pointer revappend(scheme *sc, pointer a, pointer b);
+static void dump_stack_mark(scheme *);
+static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
+static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
+static void assign_syntax(scheme *sc, char *name);
+static int syntaxnum(pointer p);
+static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
+
+#define num_ivalue(n)       (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
+#define num_rvalue(n)       (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
+
+static num num_add(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+     ret.value.ivalue= a.value.ivalue+b.value.ivalue;
+ } else {
+     ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_mul(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+     ret.value.ivalue= a.value.ivalue*b.value.ivalue;
+ } else {
+     ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_div(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
+ if(ret.is_fixnum) {
+     ret.value.ivalue= a.value.ivalue/b.value.ivalue;
+ } else {
+     ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_intdiv(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+     ret.value.ivalue= a.value.ivalue/b.value.ivalue;
+ } else {
+     ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_sub(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+     ret.value.ivalue= a.value.ivalue-b.value.ivalue;
+ } else {
+     ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_rem(num a, num b) {
+ num ret;
+ long e1, e2, res;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ e1=num_ivalue(a);
+ e2=num_ivalue(b);
+ res=e1%e2;
+ /* remainder should have same sign as second operand */
+ if (res > 0) {
+     if (e1 < 0) {
+        res -= labs(e2);
+     }
+ } else if (res < 0) {
+     if (e1 > 0) {
+         res += labs(e2);
+     }
+ }
+ ret.value.ivalue=res;
+ return ret;
+}
+
+static num num_mod(num a, num b) {
+ num ret;
+ long e1, e2, res;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ e1=num_ivalue(a);
+ e2=num_ivalue(b);
+ res=e1%e2;
+ /* modulo should have same sign as second operand */
+ if (res * e2 < 0) {
+    res += e2;
+ }
+ ret.value.ivalue=res;
+ return ret;
+}
+
+static int num_eq(num a, num b) {
+ int ret;
+ int is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(is_fixnum) {
+     ret= a.value.ivalue==b.value.ivalue;
+ } else {
+     ret=num_rvalue(a)==num_rvalue(b);
+ }
+ return ret;
+}
+
+
+static int num_gt(num a, num b) {
+ int ret;
+ int is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(is_fixnum) {
+     ret= a.value.ivalue>b.value.ivalue;
+ } else {
+     ret=num_rvalue(a)>num_rvalue(b);
+ }
+ return ret;
+}
+
+static int num_ge(num a, num b) {
+ return !num_lt(a,b);
+}
+
+static int num_lt(num a, num b) {
+ int ret;
+ int is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(is_fixnum) {
+     ret= a.value.ivalue<b.value.ivalue;
+ } else {
+     ret=num_rvalue(a)<num_rvalue(b);
+ }
+ return ret;
+}
+
+static int num_le(num a, num b) {
+ return !num_gt(a,b);
+}
+
+#if USE_MATH
+/* Round to nearest. Round to even if midway */
+static double round_per_R5RS(double x) {
+ double fl=floor(x);
+ double ce=ceil(x);
+ double dfl=x-fl;
+ double dce=ce-x;
+ if(dfl>dce) {
+     return ce;
+ } else if(dfl<dce) {
+     return fl;
+ } else {
+     if(fmod(fl,2.0)==0.0) {       /* I imagine this holds */
+          return fl;
+     } else {
+          return ce;
+     }
+ }
+}
+#endif
+
+static int is_zero_double(double x) {
+ return x<DBL_MIN && x>-DBL_MIN;
+}
+
+static long binary_decode(const char *s) {
+ long x=0;
+
+ while(*s!=0 && (*s=='1' || *s=='0')) {
+     x<<=1;
+     x+=*s-'0';
+     s++;
+ }
+
+ return x;
+}
+
+/* allocate new cell segment */
+static int alloc_cellseg(scheme *sc, int n) {
+     pointer newp;
+     pointer last;
+     pointer p;
+     char *cp;
+     long i;
+     int k;
+     int adj=ADJ;
+
+     if(adj<sizeof(struct cell)) {
+       adj=sizeof(struct cell);
+     }
+
+     for (k = 0; k < n; k++) {
+         if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
+              return k;
+         cp = (char*) sc->malloc(CELL_SEGSIZE * sizeof(struct cell)+adj);
+         if (cp == 0)
+              return k;
+         i = ++sc->last_cell_seg ;
+         sc->alloc_seg[i] = cp;
+         /* adjust in TYPE_BITS-bit boundary */
+         if(((unsigned long)cp)%adj!=0) {
+           cp=(char*)(adj*((unsigned long)cp/adj+1));
+         }
+         /* insert new segment in address order */
+         newp=(pointer)cp;
+         sc->cell_seg[i] = newp;
+         while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
+             p = sc->cell_seg[i];
+             sc->cell_seg[i] = sc->cell_seg[i - 1];
+             sc->cell_seg[--i] = p;
+         }
+         sc->fcells += CELL_SEGSIZE;
+         last = newp + CELL_SEGSIZE - 1;
+         for (p = newp; p <= last; p++) {
+              typeflag(p) = 0;
+              cdr(p) = p + 1;
+              car(p) = sc->NIL;
+         }
+         /* insert new cells in address order on free list */
+         if (sc->free_cell == sc->NIL || p < sc->free_cell) {
+              cdr(last) = sc->free_cell;
+              sc->free_cell = newp;
+         } else {
+               p = sc->free_cell;
+               while (cdr(p) != sc->NIL && newp > cdr(p))
+                    p = cdr(p);
+               cdr(last) = cdr(p);
+               cdr(p) = newp;
+         }
+     }
+     return n;
+}
+
+static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
+  if (sc->free_cell != sc->NIL) {
+    pointer x = sc->free_cell;
+    sc->free_cell = cdr(x);
+    --sc->fcells;
+    return (x);
+  }
+  return _get_cell (sc, a, b);
+}
+
+
+/* get new cell.  parameter a, b is marked by gc. */
+static pointer _get_cell(scheme *sc, pointer a, pointer b) {
+  pointer x;
+
+  if(sc->no_memory) {
+    return sc->sink;
+  }
+
+  if (sc->free_cell == sc->NIL) {
+    const int min_to_be_recovered = sc->last_cell_seg*8;
+    gc(sc,a, b);
+    if (sc->fcells < min_to_be_recovered
+        || sc->free_cell == sc->NIL) {
+      /* if only a few recovered, get more to avoid fruitless gc's */
+      if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
+        sc->no_memory=1;
+        return sc->sink;
+      }
+    }
+  }
+  x = sc->free_cell;
+  sc->free_cell = cdr(x);
+  --sc->fcells;
+  return (x);
+}
+
+/* make sure that there is a given number of cells free */
+static pointer reserve_cells(scheme *sc, int n) {
+    if(sc->no_memory) {
+        return sc->NIL;
+    }
+
+    /* Are there enough cells available? */
+    if (sc->fcells < n) {
+        /* If not, try gc'ing some */
+        gc(sc, sc->NIL, sc->NIL);
+        if (sc->fcells < n) {
+            /* If there still aren't, try getting more heap */
+            if (!alloc_cellseg(sc,1)) {
+                sc->no_memory=1;
+                return sc->NIL;
+            }
+        }
+        if (sc->fcells < n) {
+            /* If all fail, report failure */
+            sc->no_memory=1;
+            return sc->NIL;
+        }
+    }
+    return (sc->T);
+}
+
+static pointer get_consecutive_cells(scheme *sc, int n) {
+  pointer x;
+
+  if(sc->no_memory) { return sc->sink; }
+
+  /* Are there any cells available? */
+  x=find_consecutive_cells(sc,n);
+  if (x != sc->NIL) { return x; }
+
+  /* If not, try gc'ing some */
+  gc(sc, sc->NIL, sc->NIL);
+  x=find_consecutive_cells(sc,n);
+  if (x != sc->NIL) { return x; }
+
+  /* If there still aren't, try getting more heap */
+  if (!alloc_cellseg(sc,1))
+    {
+      sc->no_memory=1;
+      return sc->sink;
+    }
+
+  x=find_consecutive_cells(sc,n);
+  if (x != sc->NIL) { return x; }
+
+  /* If all fail, report failure */
+  sc->no_memory=1;
+  return sc->sink;
+}
+
+static int count_consecutive_cells(pointer x, int needed) {
+ int n=1;
+ while(cdr(x)==x+1) {
+     x=cdr(x);
+     n++;
+     if(n>needed) return n;
+ }
+ return n;
+}
+
+static pointer find_consecutive_cells(scheme *sc, int n) {
+  pointer *pp;
+  int cnt;
+
+  pp=&sc->free_cell;
+  while(*pp!=sc->NIL) {
+    cnt=count_consecutive_cells(*pp,n);
+    if(cnt>=n) {
+      pointer x=*pp;
+      *pp=cdr(*pp+n-1);
+      sc->fcells -= n;
+      return x;
+    }
+    pp=&cdr(*pp+cnt-1);
+  }
+  return sc->NIL;
+}
+
+/* To retain recent allocs before interpreter knows about them -
+   Tehom */
+
+static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
+{
+  pointer holder = get_cell_x(sc, recent, extra);
+  typeflag(holder) = T_PAIR | T_IMMUTABLE;
+  car(holder) = recent;
+  cdr(holder) = car(sc->sink);
+  car(sc->sink) = holder;
+}
+
+
+static pointer get_cell(scheme *sc, pointer a, pointer b)
+{
+  pointer cell   = get_cell_x(sc, a, b);
+  /* For right now, include "a" and "b" in "cell" so that gc doesn't
+     think they are garbage. */
+  /* Tentatively record it as a pair so gc understands it. */
+  typeflag(cell) = T_PAIR;
+  car(cell) = a;
+  cdr(cell) = b;
+  push_recent_alloc(sc, cell, sc->NIL);
+  return cell;
+}
+
+static pointer get_vector_object(scheme *sc, int len, pointer init)
+{
+  pointer cells = get_consecutive_cells(sc,len/2+len%2+1);
+  if(sc->no_memory) { return sc->sink; }
+  /* Record it as a vector so that gc understands it. */
+  typeflag(cells) = (T_VECTOR | T_ATOM);
+  ivalue_unchecked(cells)=len;
+  set_num_integer(cells);
+  fill_vector(cells,init);
+  push_recent_alloc(sc, cells, sc->NIL);
+  return cells;
+}
+
+static INLINE void ok_to_freely_gc(scheme *sc)
+{
+  car(sc->sink) = sc->NIL;
+}
+
+
+#if defined TSGRIND
+static void check_cell_alloced(pointer p, int expect_alloced)
+{
+  /* Can't use putstr(sc,str) because callers have no access to
+     sc.  */
+  if(typeflag(p) & !expect_alloced)
+    {
+      fprintf(stderr,"Cell is already allocated!\n");
+    }
+  if(!(typeflag(p)) & expect_alloced)
+    {
+      fprintf(stderr,"Cell is not allocated!\n");
+    }
+
+}
+static void check_range_alloced(pointer p, int n, int expect_alloced)
+{
+  int i;
+  for(i = 0;i<n;i++)
+    { (void)check_cell_alloced(p+i,expect_alloced); }
+}
+
+#endif
+
+/* Medium level cell allocation */
+
+/* get new cons cell */
+pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
+  pointer x = get_cell(sc,a, b);
+
+  typeflag(x) = T_PAIR;
+  if(immutable) {
+    setimmutable(x);
+  }
+  car(x) = a;
+  cdr(x) = b;
+  return (x);
+}
+
+/* ========== oblist implementation  ========== */
+
+#ifndef USE_OBJECT_LIST
+
+static int hash_fn(const char *key, int table_size);
+
+static pointer oblist_initial_value(scheme *sc)
+{
+  return mk_vector(sc, 461); /* probably should be bigger */
+}
+
+/* returns the new symbol */
+static pointer oblist_add_by_name(scheme *sc, const char *name)
+{
+  pointer x;
+  int location;
+
+  x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
+  typeflag(x) = T_SYMBOL;
+  setimmutable(car(x));
+
+  location = hash_fn(name, ivalue_unchecked(sc->oblist));
+  set_vector_elem(sc->oblist, location,
+                  immutable_cons(sc, x, vector_elem(sc->oblist, location)));
+  return x;
+}
+
+static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
+{
+  int location;
+  pointer x;
+  char *s;
+
+  location = hash_fn(name, ivalue_unchecked(sc->oblist));
+  for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) {
+    s = symname(car(x));
+    /* case-insensitive, per R5RS section 2. */
+    if(stricmp(name, s) == 0) {
+      return car(x);
+    }
+  }
+  return sc->NIL;
+}
+
+static pointer oblist_all_symbols(scheme *sc)
+{
+  int i;
+  pointer x;
+  pointer ob_list = sc->NIL;
+
+  for (i = 0; i < ivalue_unchecked(sc->oblist); i++) {
+    for (x  = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
+      ob_list = cons(sc, x, ob_list);
+    }
+  }
+  return ob_list;
+}
+
+#else
+
+static pointer oblist_initial_value(scheme *sc)
+{
+  return sc->NIL;
+}
+
+static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
+{
+     pointer x;
+     char    *s;
+
+     for (x = sc->oblist; x != sc->NIL; x = cdr(x)) {
+        s = symname(car(x));
+        /* case-insensitive, per R5RS section 2. */
+        if(stricmp(name, s) == 0) {
+          return car(x);
+        }
+     }
+     return sc->NIL;
+}
+
+/* returns the new symbol */
+static pointer oblist_add_by_name(scheme *sc, const char *name)
+{
+  pointer x;
+
+  x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
+  typeflag(x) = T_SYMBOL;
+  setimmutable(car(x));
+  sc->oblist = immutable_cons(sc, x, sc->oblist);
+  return x;
+}
+static pointer oblist_all_symbols(scheme *sc)
+{
+  return sc->oblist;
+}
+
+#endif
+
+static pointer mk_port(scheme *sc, port *p) {
+  pointer x = get_cell(sc, sc->NIL, sc->NIL);
+
+  typeflag(x) = T_PORT|T_ATOM;
+  x->_object._port=p;
+  return (x);
+}
+
+pointer mk_foreign_func(scheme *sc, foreign_func f) {
+  pointer x = get_cell(sc, sc->NIL, sc->NIL);
+
+  typeflag(x) = (T_FOREIGN | T_ATOM);
+  x->_object._ff=f;
+  return (x);
+}
+
+pointer mk_foreign_object(scheme *sc, const foreign_object_vtable *vtable, void *data) {
+  pointer x = get_cell(sc, sc->NIL, sc->NIL);
+
+  typeflag(x) = (T_FOREIGN_OBJECT | T_ATOM);
+  x->_object._foreign_object._vtable=vtable;
+  x->_object._foreign_object._data = data;
+  return (x);
+}
+
+INTERFACE pointer mk_character(scheme *sc, int c) {
+  pointer x = get_cell(sc,sc->NIL, sc->NIL);
+
+  typeflag(x) = (T_CHARACTER | T_ATOM);
+  ivalue_unchecked(x)= c;
+  set_num_integer(x);
+  return (x);
+}
+
+/* get number atom (integer) */
+INTERFACE pointer mk_integer(scheme *sc, long n) {
+  pointer x = get_cell(sc,sc->NIL, sc->NIL);
+
+  typeflag(x) = (T_NUMBER | T_ATOM);
+  ivalue_unchecked(x)= n;
+  set_num_integer(x);
+  return (x);
+}
+
+INTERFACE pointer mk_real(scheme *sc, double n) {
+  pointer x = get_cell(sc,sc->NIL, sc->NIL);
+
+  typeflag(x) = (T_NUMBER | T_ATOM);
+  rvalue_unchecked(x)= n;
+  set_num_real(x);
+  return (x);
+}
+
+static pointer mk_number(scheme *sc, num n) {
+ if(n.is_fixnum) {
+     return mk_integer(sc,n.value.ivalue);
+ } else {
+     return mk_real(sc,n.value.rvalue);
+ }
+}
+
+/* allocate name to string area */
+static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
+     char *q;
+
+     q=(char*)sc->malloc(len_str+1);
+     if(q==0) {
+          sc->no_memory=1;
+          return sc->strbuff;
+     }
+     if(str!=0) {
+         memcpy (q, str, len_str);
+          q[len_str]=0;
+     } else {
+          memset(q, fill, len_str);
+          q[len_str]=0;
+     }
+     return (q);
+}
+
+/* get new string */
+INTERFACE pointer mk_string(scheme *sc, const char *str) {
+     return mk_counted_string(sc,str,strlen(str));
+}
+
+INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
+     pointer x = get_cell(sc, sc->NIL, sc->NIL);
+     typeflag(x) = (T_STRING | T_ATOM);
+     strvalue(x) = store_string(sc,len,str,0);
+     strlength(x) = len;
+     return (x);
+}
+
+INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
+     pointer x = get_cell(sc, sc->NIL, sc->NIL);
+     typeflag(x) = (T_STRING | T_ATOM);
+     strvalue(x) = store_string(sc,len,0,fill);
+     strlength(x) = len;
+     return (x);
+}
+
+INTERFACE static pointer mk_vector(scheme *sc, int len)
+{ return get_vector_object(sc,len,sc->NIL); }
+
+INTERFACE static void fill_vector(pointer vec, pointer obj) {
+     int i;
+     int n = ivalue(vec)/2+ivalue(vec)%2;
+     for(i=0; i < n; i++) {
+          typeflag(vec+1+i) = T_PAIR;
+          setimmutable(vec+1+i);
+          car(vec+1+i)=obj;
+          cdr(vec+1+i)=obj;
+     }
+}
+
+INTERFACE static pointer vector_elem(pointer vec, int ielem) {
+     int n=ielem/2;
+     if(ielem%2==0) {
+          return car(vec+1+n);
+     } else {
+          return cdr(vec+1+n);
+     }
+}
+
+INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
+     int n=ielem/2;
+     if(ielem%2==0) {
+          return car(vec+1+n)=a;
+     } else {
+          return cdr(vec+1+n)=a;
+     }
+}
+
+/* get new symbol */
+INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
+     pointer x;
+
+     /* first check oblist */
+     x = oblist_find_by_name(sc, name);
+     if (x != sc->NIL) {
+          return (x);
+     } else {
+          x = oblist_add_by_name(sc, name);
+          return (x);
+     }
+}
+
+INTERFACE pointer gensym(scheme *sc) {
+     pointer x;
+     char name[40];
+
+     for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
+          snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
+
+          /* first check oblist */
+          x = oblist_find_by_name(sc, name);
+
+          if (x != sc->NIL) {
+               continue;
+          } else {
+               x = oblist_add_by_name(sc, name);
+               return (x);
+          }
+     }
+
+     return sc->NIL;
+}
+
+/* double the size of the string buffer */
+static int expand_strbuff(scheme *sc) {
+  size_t new_size = sc->strbuff_size * 2;
+  char *new_buffer = sc->malloc(new_size);
+  if (new_buffer == 0) {
+    sc->no_memory = 1;
+    return 1;
+  }
+  memcpy(new_buffer, sc->strbuff, sc->strbuff_size);
+  sc->free(sc->strbuff);
+  sc->strbuff = new_buffer;
+  sc->strbuff_size = new_size;
+  return 0;
+}
+
+/* make symbol or number atom from string */
+static pointer mk_atom(scheme *sc, char *q) {
+     char    c, *p;
+     int has_dec_point=0;
+     int has_fp_exp = 0;
+
+#if USE_COLON_HOOK
+     if((p=strstr(q,"::"))!=0) {
+          *p=0;
+          return cons(sc, sc->COLON_HOOK,
+                          cons(sc,
+                              cons(sc,
+                                   sc->QUOTE,
+                                   cons(sc, mk_atom(sc,p+2), sc->NIL)),
+                              cons(sc, mk_symbol(sc,strlwr(q)), sc->NIL)));
+     }
+#endif
+
+     p = q;
+     c = *p++;
+     if ((c == '+') || (c == '-')) {
+       c = *p++;
+       if (c == '.') {
+         has_dec_point=1;
+         c = *p++;
+       }
+       if (!isdigit(c)) {
+         return (mk_symbol(sc, strlwr(q)));
+       }
+     } else if (c == '.') {
+       has_dec_point=1;
+       c = *p++;
+       if (!isdigit(c)) {
+         return (mk_symbol(sc, strlwr(q)));
+       }
+     } else if (!isdigit(c)) {
+       return (mk_symbol(sc, strlwr(q)));
+     }
+
+     for ( ; (c = *p) != 0; ++p) {
+          if (!isdigit(c)) {
+               if(c=='.') {
+                    if(!has_dec_point) {
+                         has_dec_point=1;
+                         continue;
+                    }
+               }
+               else if ((c == 'e') || (c == 'E')) {
+                       if(!has_fp_exp) {
+                          has_dec_point = 1; /* decimal point illegal
+                                                from now on */
+                          p++;
+                          if ((*p == '-') || (*p == '+') || isdigit(*p)) {
+                             continue;
+                          }
+                       }
+               }
+               return (mk_symbol(sc, strlwr(q)));
+          }
+     }
+     if(has_dec_point) {
+          return mk_real(sc,atof(q));
+     }
+     return (mk_integer(sc, atol(q)));
+}
+
+/* make constant */
+static pointer mk_sharp_const(scheme *sc, char *name) {
+     long    x;
+     char    tmp[STRBUFFSIZE];
+
+     if (!strcmp(name, "t"))
+          return (sc->T);
+     else if (!strcmp(name, "f"))
+          return (sc->F);
+     else if (*name == 'o') {/* #o (octal) */
+          snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
+          sscanf(tmp, "%lo", (long unsigned *)&x);
+          return (mk_integer(sc, x));
+     } else if (*name == 'd') {    /* #d (decimal) */
+          sscanf(name+1, "%ld", (long int *)&x);
+          return (mk_integer(sc, x));
+     } else if (*name == 'x') {    /* #x (hex) */
+          snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
+          sscanf(tmp, "%lx", (long unsigned *)&x);
+          return (mk_integer(sc, x));
+     } else if (*name == 'b') {    /* #b (binary) */
+          x = binary_decode(name+1);
+          return (mk_integer(sc, x));
+     } else if (*name == '\\') { /* #\w (character) */
+          int c=0;
+          if(stricmp(name+1,"space")==0) {
+               c=' ';
+          } else if(stricmp(name+1,"newline")==0) {
+               c='\n';
+          } else if(stricmp(name+1,"return")==0) {
+               c='\r';
+          } else if(stricmp(name+1,"tab")==0) {
+               c='\t';
+     } else if(name[1]=='x' && name[2]!=0) {
+          int c1=0;
+          if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
+               c=c1;
+          } else {
+               return sc->NIL;
+     }
+#if USE_ASCII_NAMES
+          } else if(is_ascii_name(name+1,&c)) {
+               /* nothing */
+#endif
+          } else if(name[2]==0) {
+               c=name[1];
+          } else {
+               return sc->NIL;
+          }
+          return mk_character(sc,c);
+     } else
+          return (sc->NIL);
+}
+
+/* ========== garbage collector ========== */
+
+/*--
+ *  We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
+ *  sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
+ *  for marking.
+ */
+static void mark(pointer a) {
+     pointer t, q, p;
+
+     t = (pointer) 0;
+     p = a;
+E2:  setmark(p);
+     if(is_vector(p)) {
+          int i;
+          int n = ivalue_unchecked(p)/2+ivalue_unchecked(p)%2;
+          for(i=0; i < n; i++) {
+               /* Vector cells will be treated like ordinary cells */
+               mark(p+1+i);
+          }
+     }
+     if (is_atom(p))
+          goto E6;
+     /* E4: down car */
+     q = car(p);
+     if (q && !is_mark(q)) {
+          setatom(p);  /* a note that we have moved car */
+          car(p) = t;
+          t = p;
+          p = q;
+          goto E2;
+     }
+E5:  q = cdr(p); /* down cdr */
+     if (q && !is_mark(q)) {
+          cdr(p) = t;
+          t = p;
+          p = q;
+          goto E2;
+     }
+E6:   /* up.  Undo the link switching from steps E4 and E5. */
+     if (!t)
+          return;
+     q = t;
+     if (is_atom(q)) {
+          clratom(q);
+          t = car(q);
+          car(q) = p;
+          p = q;
+          goto E5;
+     } else {
+          t = cdr(q);
+          cdr(q) = p;
+          p = q;
+          goto E6;
+     }
+}
+
+/* garbage collection. parameter a, b is marked. */
+static void gc(scheme *sc, pointer a, pointer b) {
+  pointer p;
+  int i;
+
+  if(sc->gc_verbose) {
+    putstr(sc, "gc...");
+  }
+
+  /* mark system globals */
+  mark(sc->oblist);
+  mark(sc->global_env);
+
+  /* mark current registers */
+  mark(sc->args);
+  mark(sc->envir);
+  mark(sc->code);
+  dump_stack_mark(sc);
+  mark(sc->value);
+  mark(sc->inport);
+  mark(sc->save_inport);
+  mark(sc->outport);
+  mark(sc->loadport);
+
+  /* Mark recent objects the interpreter doesn't know about yet. */
+  mark(car(sc->sink));
+  /* Mark any older stuff above nested C calls */
+  mark(sc->c_nest);
+
+  /* mark variables a, b */
+  mark(a);
+  mark(b);
+
+  /* garbage collect */
+  clrmark(sc->NIL);
+  sc->fcells = 0;
+  sc->free_cell = sc->NIL;
+  /* free-list is kept sorted by address so as to maintain consecutive
+     ranges, if possible, for use with vectors. Here we scan the cells
+     (which are also kept sorted by address) downwards to build the
+     free-list in sorted order.
+  */
+  for (i = sc->last_cell_seg; i >= 0; i--) {
+    p = sc->cell_seg[i] + CELL_SEGSIZE;
+    while (--p >= sc->cell_seg[i]) {
+      if (is_mark(p)) {
+    clrmark(p);
+      } else {
+    /* reclaim cell */
+        if (typeflag(p) != 0) {
+          finalize_cell(sc, p);
+          typeflag(p) = 0;
+          car(p) = sc->NIL;
+        }
+        ++sc->fcells;
+        cdr(p) = sc->free_cell;
+        sc->free_cell = p;
+      }
+    }
+  }
+
+  if (sc->gc_verbose) {
+    char msg[80];
+    snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
+    putstr(sc,msg);
+  }
+}
+
+static void finalize_cell(scheme *sc, pointer a) {
+  if(is_string(a)) {
+    sc->free(strvalue(a));
+  } else if(is_port(a)) {
+    if(a->_object._port->kind&port_file
+       && a->_object._port->rep.stdio.closeit) {
+      port_close(sc,a,port_input|port_output);
+    } else if (a->_object._port->kind & port_srfi6) {
+      sc->free(a->_object._port->rep.string.start);
+    }
+    sc->free(a->_object._port);
+  } else if(is_foreign_object(a)) {
+    a->_object._foreign_object._vtable->finalize(sc, a->_object._foreign_object._data);
+  }
+}
+
+/* ========== Routines for Reading ========== */
+
+static int file_push(scheme *sc, const char *fname) {
+  FILE *fin = NULL;
+
+  if (sc->file_i == MAXFIL-1)
+     return 0;
+  fin=fopen(fname,"r");
+  if(fin!=0) {
+    sc->file_i++;
+    sc->load_stack[sc->file_i].kind=port_file|port_input;
+    sc->load_stack[sc->file_i].rep.stdio.file=fin;
+    sc->load_stack[sc->file_i].rep.stdio.closeit=1;
+    sc->nesting_stack[sc->file_i]=0;
+    sc->loadport->_object._port=sc->load_stack+sc->file_i;
+
+#if SHOW_ERROR_LINE
+    sc->load_stack[sc->file_i].rep.stdio.curr_line = 0;
+    if(fname)
+      sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0);
+#endif
+  }
+  return fin!=0;
+}
+
+static void file_pop(scheme *sc) {
+ if(sc->file_i != 0) {
+   sc->nesting=sc->nesting_stack[sc->file_i];
+   port_close(sc,sc->loadport,port_input);
+   sc->file_i--;
+   sc->loadport->_object._port=sc->load_stack+sc->file_i;
+ }
+}
+
+static int file_interactive(scheme *sc) {
+ return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
+     && sc->inport->_object._port->kind&port_file;
+}
+
+static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
+  FILE *f;
+  char *rw;
+  port *pt;
+  if(prop==(port_input|port_output)) {
+    rw="a+";
+  } else if(prop==port_output) {
+    rw="w";
+  } else {
+    rw="r";
+  }
+  f=fopen(fn,rw);
+  if(f==0) {
+    return 0;
+  }
+  pt=port_rep_from_file(sc,f,prop);
+  pt->rep.stdio.closeit=1;
+
+#if SHOW_ERROR_LINE
+  if(fn)
+    pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0);
+
+  pt->rep.stdio.curr_line = 0;
+#endif
+  return pt;
+}
+
+static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
+  port *pt;
+  pt=port_rep_from_filename(sc,fn,prop);
+  if(pt==0) {
+    return sc->NIL;
+  }
+  return mk_port(sc,pt);
+}
+
+static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
+{
+    port *pt;
+
+    pt = (port *)sc->malloc(sizeof *pt);
+    if (pt == NULL) {
+        return NULL;
+    }
+    pt->kind = port_file | prop;
+    pt->rep.stdio.file = f;
+    pt->rep.stdio.closeit = 0;
+    return pt;
+}
+
+static pointer port_from_file(scheme *sc, FILE *f, int prop) {
+  port *pt;
+  pt=port_rep_from_file(sc,f,prop);
+  if(pt==0) {
+    return sc->NIL;
+  }
+  return mk_port(sc,pt);
+}
+
+static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
+  port *pt;
+  pt=(port*)sc->malloc(sizeof(port));
+  if(pt==0) {
+    return 0;
+  }
+  pt->kind=port_string|prop;
+  pt->rep.string.start=start;
+  pt->rep.string.curr=start;
+  pt->rep.string.past_the_end=past_the_end;
+  return pt;
+}
+
+static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
+  port *pt;
+  pt=port_rep_from_string(sc,start,past_the_end,prop);
+  if(pt==0) {
+    return sc->NIL;
+  }
+  return mk_port(sc,pt);
+}
+
+#define BLOCK_SIZE 256
+
+static port *port_rep_from_scratch(scheme *sc) {
+  port *pt;
+  char *start;
+  pt=(port*)sc->malloc(sizeof(port));
+  if(pt==0) {
+    return 0;
+  }
+  start=sc->malloc(BLOCK_SIZE);
+  if(start==0) {
+    return 0;
+  }
+  memset(start,' ',BLOCK_SIZE-1);
+  start[BLOCK_SIZE-1]='\0';
+  pt->kind=port_string|port_output|port_srfi6;
+  pt->rep.string.start=start;
+  pt->rep.string.curr=start;
+  pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
+  return pt;
+}
+
+static pointer port_from_scratch(scheme *sc) {
+  port *pt;
+  pt=port_rep_from_scratch(sc);
+  if(pt==0) {
+    return sc->NIL;
+  }
+  return mk_port(sc,pt);
+}
+
+static void port_close(scheme *sc, pointer p, int flag) {
+  port *pt=p->_object._port;
+  pt->kind&=~flag;
+  if((pt->kind & (port_input|port_output))==0) {
+    if(pt->kind&port_file) {
+
+#if SHOW_ERROR_LINE
+      /* Cleanup is here so (close-*-port) functions could work too */
+      pt->rep.stdio.curr_line = 0;
+
+      if(pt->rep.stdio.filename)
+        sc->free(pt->rep.stdio.filename);
+#endif
+
+      fclose(pt->rep.stdio.file);
+    }
+    pt->kind=port_free;
+  }
+}
+
+/* get new character from input file */
+static int inchar(scheme *sc) {
+  int c;
+  port *pt;
+
+  pt = sc->inport->_object._port;
+  if(pt->kind & port_saw_EOF)
+    { return EOF; }
+  c = basic_inchar(pt);
+  if(c == EOF && sc->inport == sc->loadport) {
+    /* Instead, set port_saw_EOF */
+    pt->kind |= port_saw_EOF;
+
+    /* file_pop(sc); */
+    return EOF;
+    /* NOTREACHED */
+  }
+  return c;
+}
+
+static int basic_inchar(port *pt) {
+  if(pt->kind & port_file) {
+    return fgetc(pt->rep.stdio.file);
+  } else {
+    if(*pt->rep.string.curr == 0 ||
+       pt->rep.string.curr == pt->rep.string.past_the_end) {
+      return EOF;
+    } else {
+      return *pt->rep.string.curr++;
+    }
+  }
+}
+
+/* back character to input buffer */
+static void backchar(scheme *sc, int c) {
+  port *pt;
+  if(c==EOF) return;
+  pt=sc->inport->_object._port;
+  if(pt->kind&port_file) {
+    ungetc(c,pt->rep.stdio.file);
+  } else {
+    if(pt->rep.string.curr!=pt->rep.string.start) {
+      --pt->rep.string.curr;
+    }
+  }
+}
+
+static int realloc_port_string(scheme *sc, port *p)
+{
+  char *start=p->rep.string.start;
+  size_t old_size = p->rep.string.past_the_end - start;
+  size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
+  char *str=sc->malloc(new_size);
+  if(str) {
+    memset(str,' ',new_size-1);
+    str[new_size-1]='\0';
+    memcpy(str, start, old_size);
+    p->rep.string.start=str;
+    p->rep.string.past_the_end=str+new_size-1;
+    p->rep.string.curr-=start-str;
+    sc->free(start);
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+INTERFACE void putstr(scheme *sc, const char *s) {
+  port *pt=sc->outport->_object._port;
+  if(pt->kind&port_file) {
+    fputs(s,pt->rep.stdio.file);
+  } else {
+    for(;*s;s++) {
+      if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
+        *pt->rep.string.curr++=*s;
+      } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
+        *pt->rep.string.curr++=*s;
+      }
+    }
+  }
+}
+
+static void putchars(scheme *sc, const char *s, int len) {
+  port *pt=sc->outport->_object._port;
+  if(pt->kind&port_file) {
+    fwrite(s,1,len,pt->rep.stdio.file);
+  } else {
+    for(;len;len--) {
+      if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
+        *pt->rep.string.curr++=*s++;
+      } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
+        *pt->rep.string.curr++=*s++;
+      }
+    }
+  }
+}
+
+INTERFACE void putcharacter(scheme *sc, int c) {
+  port *pt=sc->outport->_object._port;
+  if(pt->kind&port_file) {
+    fputc(c,pt->rep.stdio.file);
+  } else {
+    if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
+      *pt->rep.string.curr++=c;
+    } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
+        *pt->rep.string.curr++=c;
+    }
+  }
+}
+
+/* read characters up to delimiter, but cater to character constants */
+static char *readstr_upto(scheme *sc, char *delim) {
+  char *p = sc->strbuff;
+
+  while ((p - sc->strbuff < sc->strbuff_size) &&
+         !is_one_of(delim, (*p++ = inchar(sc))));
+
+  if(p == sc->strbuff+2 && p[-2] == '\\') {
+    *p=0;
+  } else {
+    backchar(sc,p[-1]);
+    *--p = '\0';
+  }
+  return sc->strbuff;
+}
+
+/* read string expression "xxx...xxx" */
+static pointer readstrexp(scheme *sc) {
+  char *p = sc->strbuff;
+  int c;
+  int c1=0;
+  enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
+
+  for (;;) {
+    c=inchar(sc);
+    if(c == EOF) {
+      return sc->F;
+    }
+    if(p-sc->strbuff > (sc->strbuff_size)-1) {
+      ptrdiff_t offset = p - sc->strbuff;
+      if (expand_strbuff(sc) != 0) {
+        return sc->F;
+      }
+      p = sc->strbuff + offset;
+    }
+    switch(state) {
+        case st_ok:
+            switch(c) {
+                case '\\':
+                    state=st_bsl;
+                    break;
+                case '"':
+                    *p=0;
+                    return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
+                default:
+                    *p++=c;
+                    break;
+            }
+            break;
+        case st_bsl:
+            switch(c) {
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                        state=st_oct1;
+                        c1=c-'0';
+                        break;
+                case 'x':
+                case 'X':
+                    state=st_x1;
+                    c1=0;
+                    break;
+                case 'n':
+                    *p++='\n';
+                    state=st_ok;
+                    break;
+                case 't':
+                    *p++='\t';
+                    state=st_ok;
+                    break;
+                case 'r':
+                    *p++='\r';
+                    state=st_ok;
+                    break;
+                case '"':
+                    *p++='"';
+                    state=st_ok;
+                    break;
+                default:
+                    *p++=c;
+                    state=st_ok;
+                    break;
+            }
+            break;
+        case st_x1:
+        case st_x2:
+            c=toupper(c);
+            if(c>='0' && c<='F') {
+                if(c<='9') {
+                    c1=(c1<<4)+c-'0';
+                } else {
+                    c1=(c1<<4)+c-'A'+10;
+                }
+                if(state==st_x1) {
+                    state=st_x2;
+                } else {
+                    *p++=c1;
+                    state=st_ok;
+                }
+            } else {
+                return sc->F;
+            }
+            break;
+        case st_oct1:
+        case st_oct2:
+            if (c < '0' || c > '7')
+            {
+                   *p++=c1;
+                   backchar(sc, c);
+                   state=st_ok;
+            }
+            else
+            {
+                if (state==st_oct2 && c1 >= 32)
+                    return sc->F;
+
+                   c1=(c1<<3)+(c-'0');
+
+                if (state == st_oct1)
+                        state=st_oct2;
+                else
+                {
+                        *p++=c1;
+                        state=st_ok;
+                   }
+            }
+            break;
+
+    }
+  }
+}
+
+/* check c is in chars */
+static INLINE int is_one_of(char *s, int c) {
+     if(c==EOF) return 1;
+     while (*s)
+          if (*s++ == c)
+               return (1);
+     return (0);
+}
+
+/* skip white characters */
+static INLINE int skipspace(scheme *sc) {
+     int c = 0, curr_line = 0;
+
+     do {
+         c=inchar(sc);
+#if SHOW_ERROR_LINE
+         if(c=='\n')
+           curr_line++;
+#endif
+     } while (isspace(c));
+
+/* record it */
+#if SHOW_ERROR_LINE
+     if (sc->load_stack[sc->file_i].kind & port_file)
+       sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line;
+#endif
+
+     if(c!=EOF) {
+          backchar(sc,c);
+      return 1;
+     }
+     else
+       { return EOF; }
+}
+
+/* get token */
+static int token(scheme *sc) {
+     int c;
+     c = skipspace(sc);
+     if(c == EOF) { return (TOK_EOF); }
+     switch (c=inchar(sc)) {
+     case EOF:
+          return (TOK_EOF);
+     case '(':
+          return (TOK_LPAREN);
+     case ')':
+          return (TOK_RPAREN);
+     case '.':
+          c=inchar(sc);
+          if(is_one_of(" \n\t",c)) {
+               return (TOK_DOT);
+          } else {
+               backchar(sc,c);
+               backchar(sc,'.');
+               return TOK_ATOM;
+          }
+     case '\'':
+          return (TOK_QUOTE);
+     case ';':
+           while ((c=inchar(sc)) != '\n' && c!=EOF)
+             ;
+
+#if SHOW_ERROR_LINE
+           if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
+             sc->load_stack[sc->file_i].rep.stdio.curr_line++;
+#endif
+
+       if(c == EOF)
+         { return (TOK_EOF); }
+       else
+         { return (token(sc));}
+     case '"':
+          return (TOK_DQUOTE);
+     case BACKQUOTE:
+          return (TOK_BQUOTE);
+     case ',':
+         if ((c=inchar(sc)) == '@') {
+               return (TOK_ATMARK);
+         } else {
+               backchar(sc,c);
+               return (TOK_COMMA);
+         }
+     case '#':
+          c=inchar(sc);
+          if (c == '(') {
+               return (TOK_VEC);
+          } else if(c == '!') {
+               while ((c=inchar(sc)) != '\n' && c!=EOF)
+                   ;
+
+#if SHOW_ERROR_LINE
+           if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
+             sc->load_stack[sc->file_i].rep.stdio.curr_line++;
+#endif
+
+           if(c == EOF)
+             { return (TOK_EOF); }
+           else
+             { return (token(sc));}
+          } else {
+               backchar(sc,c);
+               if(is_one_of(" tfodxb\\",c)) {
+                    return TOK_SHARP_CONST;
+               } else {
+                    return (TOK_SHARP);
+               }
+          }
+     default:
+          backchar(sc,c);
+          return (TOK_ATOM);
+     }
+}
+
+/* ========== Routines for Printing ========== */
+#define   ok_abbrev(x)   (is_pair(x) && cdr(x) == sc->NIL)
+
+static void printslashstring(scheme *sc, char *p, int len) {
+  int i;
+  unsigned char *s=(unsigned char*)p;
+  putcharacter(sc,'"');
+  for ( i=0; i<len; i++) {
+    if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
+      putcharacter(sc,'\\');
+      switch(*s) {
+      case '"':
+        putcharacter(sc,'"');
+        break;
+      case '\n':
+        putcharacter(sc,'n');
+        break;
+      case '\t':
+        putcharacter(sc,'t');
+        break;
+      case '\r':
+        putcharacter(sc,'r');
+        break;
+      case '\\':
+        putcharacter(sc,'\\');
+        break;
+      default: {
+          int d=*s/16;
+          putcharacter(sc,'x');
+          if(d<10) {
+            putcharacter(sc,d+'0');
+          } else {
+            putcharacter(sc,d-10+'A');
+          }
+          d=*s%16;
+          if(d<10) {
+            putcharacter(sc,d+'0');
+          } else {
+            putcharacter(sc,d-10+'A');
+          }
+        }
+      }
+    } else {
+      putcharacter(sc,*s);
+    }
+    s++;
+  }
+  putcharacter(sc,'"');
+}
+
+
+/* print atoms */
+static void printatom(scheme *sc, pointer l, int f) {
+  char *p;
+  int len;
+  atom2str(sc,l,f,&p,&len);
+  putchars(sc,p,len);
+}
+
+
+/* Uses internal buffer unless string pointer is already available */
+static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
+     char *p;
+
+     if (l == sc->NIL) {
+          p = "()";
+     } else if (l == sc->T) {
+          p = "#t";
+     } else if (l == sc->F) {
+          p = "#f";
+     } else if (l == sc->EOF_OBJ) {
+          p = "#<EOF>";
+     } else if (is_port(l)) {
+          p = "#<PORT>";
+     } else if (is_number(l)) {
+          p = sc->strbuff;
+          if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
+              if(num_is_integer(l)) {
+                   snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
+              } else {
+                   snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
+                   /* r5rs says there must be a '.' (unless 'e'?) */
+                   f = strcspn(p, ".e");
+                   if (p[f] == 0) {
+                        p[f] = '.'; /* not found, so add '.0' at the end */
+                        p[f+1] = '0';
+                        p[f+2] = 0;
+                   }
+              }
+          } else {
+              long v = ivalue(l);
+              if (f == 16) {
+                  if (v >= 0)
+                    snprintf(p, STRBUFFSIZE, "%lx", v);
+                  else
+                    snprintf(p, STRBUFFSIZE, "-%lx", -v);
+              } else if (f == 8) {
+                  if (v >= 0)
+                    snprintf(p, STRBUFFSIZE, "%lo", v);
+                  else
+                    snprintf(p, STRBUFFSIZE, "-%lo", -v);
+              } else if (f == 2) {
+                  unsigned long b = (v < 0) ? -v : v;
+                  p = &p[STRBUFFSIZE-1];
+                  *p = 0;
+                  do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
+                  if (v < 0) *--p = '-';
+              }
+          }
+     } else if (is_string(l)) {
+          if (!f) {
+               p = strvalue(l);
+          } else { /* Hack, uses the fact that printing is needed */
+               *pp=sc->strbuff;
+               *plen=0;
+               printslashstring(sc, strvalue(l), strlength(l));
+               return;
+          }
+     } else if (is_character(l)) {
+          int c=charvalue(l);
+          p = sc->strbuff;
+          if (!f) {
+               p[0]=c;
+               p[1]=0;
+          } else {
+               switch(c) {
+               case ' ':
+                    p = "#\\space";
+                    break;
+               case '\n':
+                    p = "#\\newline";
+                    break;
+               case '\r':
+                    p = "#\\return";
+                    break;
+               case '\t':
+                    p = "#\\tab";
+                    break;
+               default:
+#if USE_ASCII_NAMES
+                    if(c==127) {
+                         p = "#\\del";
+                         break;
+                    } else if(c<32) {
+                         snprintf(p,STRBUFFSIZE, "#\\%s",charnames[c]);
+                         break;
+                    }
+#else
+                    if(c<32) {
+                      snprintf(p,STRBUFFSIZE,"#\\x%x",c);
+                      break;
+                    }
+#endif
+                    snprintf(p,STRBUFFSIZE,"#\\%c",c);
+                    break;
+               }
+          }
+     } else if (is_symbol(l)) {
+          p = symname(l);
+     } else if (is_proc(l)) {
+          p = sc->strbuff;
+          snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
+     } else if (is_macro(l)) {
+          p = "#<MACRO>";
+     } else if (is_closure(l)) {
+          p = "#<CLOSURE>";
+     } else if (is_promise(l)) {
+          p = "#<PROMISE>";
+     } else if (is_foreign(l)) {
+          p = sc->strbuff;
+          snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
+     } else if (is_continuation(l)) {
+          p = "#<CONTINUATION>";
+     } else if (is_foreign_object(l)) {
+          p = sc->strbuff;
+          l->_object._foreign_object._vtable->to_string(sc, p, STRBUFFSIZE, l->_object._foreign_object._data);
+     } else {
+          p = "#<ERROR>";
+     }
+     *pp=p;
+     *plen=strlen(p);
+}
+/* ========== Routines for Evaluation Cycle ========== */
+
+/* make closure. c is code. e is environment */
+static pointer mk_closure(scheme *sc, pointer c, pointer e) {
+     pointer x = get_cell(sc, c, e);
+
+     typeflag(x) = T_CLOSURE;
+     car(x) = c;
+     cdr(x) = e;
+     return (x);
+}
+
+/* make continuation. */
+static pointer mk_continuation(scheme *sc, pointer d) {
+     pointer x = get_cell(sc, sc->NIL, d);
+
+     typeflag(x) = T_CONTINUATION;
+     cont_dump(x) = d;
+     return (x);
+}
+
+static pointer list_star(scheme *sc, pointer d) {
+  pointer p, q;
+  if(cdr(d)==sc->NIL) {
+    return car(d);
+  }
+  p=cons(sc,car(d),cdr(d));
+  q=p;
+  while(cdr(cdr(p))!=sc->NIL) {
+    d=cons(sc,car(p),cdr(p));
+    if(cdr(cdr(p))!=sc->NIL) {
+      p=cdr(d);
+    }
+  }
+  cdr(p)=car(cdr(p));
+  return q;
+}
+
+/* reverse list -- produce new list */
+static pointer reverse(scheme *sc, pointer a) {
+/* a must be checked by gc */
+     pointer p = sc->NIL;
+
+     for ( ; is_pair(a); a = cdr(a)) {
+          p = cons(sc, car(a), p);
+     }
+     return (p);
+}
+
+/* reverse list --- in-place */
+static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
+     pointer p = list, result = term, q;
+
+     while (p != sc->NIL) {
+          q = cdr(p);
+          cdr(p) = result;
+          result = p;
+          p = q;
+     }
+     return (result);
+}
+
+/* append list -- produce new list (in reverse order) */
+static pointer revappend(scheme *sc, pointer a, pointer b) {
+    pointer result = a;
+    pointer p = b;
+
+    while (is_pair(p)) {
+        result = cons(sc, car(p), result);
+        p = cdr(p);
+    }
+
+    if (p == sc->NIL) {
+        return result;
+    }
+
+    return sc->F;   /* signal an error */
+}
+
+/* equivalence of atoms */
+int eqv(pointer a, pointer b) {
+     if (is_string(a)) {
+          if (is_string(b))
+               return (strvalue(a) == strvalue(b));
+          else
+               return (0);
+     } else if (is_number(a)) {
+          if (is_number(b)) {
+               if (num_is_integer(a) == num_is_integer(b))
+                    return num_eq(nvalue(a),nvalue(b));
+          }
+          return (0);
+     } else if (is_character(a)) {
+          if (is_character(b))
+               return charvalue(a)==charvalue(b);
+          else
+               return (0);
+     } else if (is_port(a)) {
+          if (is_port(b))
+               return a==b;
+          else
+               return (0);
+     } else if (is_proc(a)) {
+          if (is_proc(b))
+               return procnum(a)==procnum(b);
+          else
+               return (0);
+     } else {
+          return (a == b);
+     }
+}
+
+/* true or false value macro */
+/* () is #t in R5RS */
+#define is_true(p)       ((p) != sc->F)
+#define is_false(p)      ((p) == sc->F)
+
+/* ========== Environment implementation  ========== */
+
+#if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
+
+static int hash_fn(const char *key, int table_size)
+{
+  unsigned int hashed = 0;
+  const char *c;
+  int bits_per_int = sizeof(unsigned int)*8;
+
+  for (c = key; *c; c++) {
+    /* letters have about 5 bits in them */
+    hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
+    hashed ^= *c;
+  }
+  return hashed % table_size;
+}
+#endif
+
+#ifndef USE_ALIST_ENV
+
+/*
+ * In this implementation, each frame of the environment may be
+ * a hash table: a vector of alists hashed by variable name.
+ * In practice, we use a vector only for the initial frame;
+ * subsequent frames are too small and transient for the lookup
+ * speed to out-weigh the cost of making a new vector.
+ */
+
+static void new_frame_in_env(scheme *sc, pointer old_env)
+{
+  pointer new_frame;
+
+  /* The interaction-environment has about 300 variables in it. */
+  if (old_env == sc->NIL) {
+    new_frame = mk_vector(sc, 461);
+  } else {
+    new_frame = sc->NIL;
+  }
+
+  sc->envir = immutable_cons(sc, new_frame, old_env);
+  setenvironment(sc->envir);
+}
+
+static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
+                                        pointer variable, pointer value)
+{
+  pointer slot = immutable_cons(sc, variable, value);
+
+  if (is_vector(car(env))) {
+    int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
+
+    set_vector_elem(car(env), location,
+                    immutable_cons(sc, slot, vector_elem(car(env), location)));
+  } else {
+    car(env) = immutable_cons(sc, slot, car(env));
+  }
+}
+
+static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
+{
+  pointer x,y;
+  int location;
+
+  for (x = env; x != sc->NIL; x = cdr(x)) {
+    if (is_vector(car(x))) {
+      location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
+      y = vector_elem(car(x), location);
+    } else {
+      y = car(x);
+    }
+    for ( ; y != sc->NIL; y = cdr(y)) {
+              if (caar(y) == hdl) {
+                   break;
+              }
+         }
+         if (y != sc->NIL) {
+              break;
+         }
+         if(!all) {
+           return sc->NIL;
+         }
+    }
+    if (x != sc->NIL) {
+          return car(y);
+    }
+    return sc->NIL;
+}
+
+#else /* USE_ALIST_ENV */
+
+static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
+{
+  sc->envir = immutable_cons(sc, sc->NIL, old_env);
+  setenvironment(sc->envir);
+}
+
+static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
+                                        pointer variable, pointer value)
+{
+  car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
+}
+
+static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
+{
+    pointer x,y;
+    for (x = env; x != sc->NIL; x = cdr(x)) {
+         for (y = car(x); y != sc->NIL; y = cdr(y)) {
+              if (caar(y) == hdl) {
+                   break;
+              }
+         }
+         if (y != sc->NIL) {
+              break;
+         }
+         if(!all) {
+           return sc->NIL;
+         }
+    }
+    if (x != sc->NIL) {
+          return car(y);
+    }
+    return sc->NIL;
+}
+
+#endif /* USE_ALIST_ENV else */
+
+static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
+{
+  new_slot_spec_in_env(sc, sc->envir, variable, value);
+}
+
+static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
+{
+  (void)sc;
+  cdr(slot) = value;
+}
+
+static INLINE pointer slot_value_in_env(pointer slot)
+{
+  return cdr(slot);
+}
+
+/* ========== Evaluation Cycle ========== */
+
+
+static pointer _Error_1(scheme *sc, const char *s, pointer a) {
+     const char *str = s;
+#if USE_ERROR_HOOK
+     pointer x;
+     pointer hdl=sc->ERROR_HOOK;
+#endif
+
+#if SHOW_ERROR_LINE
+     char sbuf[STRBUFFSIZE];
+
+     /* make sure error is not in REPL */
+     if (sc->load_stack[sc->file_i].kind & port_file &&
+         sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
+       int ln = sc->load_stack[sc->file_i].rep.stdio.curr_line;
+       const char *fname = sc->load_stack[sc->file_i].rep.stdio.filename;
+
+       /* should never happen */
+       if(!fname) fname = "<unknown>";
+
+       /* we started from 0 */
+       ln++;
+       snprintf(sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
+
+       str = (const char*)sbuf;
+     }
+#endif
+
+#if USE_ERROR_HOOK
+     x=find_slot_in_env(sc,sc->envir,hdl,1);
+    if (x != sc->NIL) {
+         if(a!=0) {
+               sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc,(a), sc->NIL)), sc->NIL);
+         } else {
+               sc->code = sc->NIL;
+         }
+         sc->code = cons(sc, mk_string(sc, str), sc->code);
+         setimmutable(car(sc->code));
+         sc->code = cons(sc, slot_value_in_env(x), sc->code);
+         sc->op = (int)OP_EVAL;
+         return sc->T;
+    }
+#endif
+
+    if(a!=0) {
+          sc->args = cons(sc, (a), sc->NIL);
+    } else {
+          sc->args = sc->NIL;
+    }
+    sc->args = cons(sc, mk_string(sc, str), sc->args);
+    setimmutable(car(sc->args));
+    sc->op = (int)OP_ERR0;
+    return sc->T;
+}
+#define Error_1(sc,s, a) return _Error_1(sc,s,a)
+#define Error_0(sc,s)    return _Error_1(sc,s,0)
+
+/* Too small to turn into function */
+# define  BEGIN     do {
+# define  END  } while (0)
+#define s_goto(sc,a) BEGIN                                  \
+    sc->op = (int)(a);                                      \
+    return sc->T; END
+
+#define s_return(sc,a) return _s_return(sc,a)
+
+#ifndef USE_SCHEME_STACK
+
+/* this structure holds all the interpreter's registers */
+struct dump_stack_frame {
+  enum scheme_opcodes op;
+  pointer args;
+  pointer envir;
+  pointer code;
+};
+
+#define STACK_GROWTH 3
+
+static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code)
+{
+  int nframes = (int)sc->dump;
+  struct dump_stack_frame *next_frame;
+
+  /* enough room for the next frame? */
+  if (nframes >= sc->dump_size) {
+    sc->dump_size += STACK_GROWTH;
+    /* alas there is no sc->realloc */
+    sc->dump_base = realloc(sc->dump_base,
+                            sizeof(struct dump_stack_frame) * sc->dump_size);
+  }
+  next_frame = (struct dump_stack_frame *)sc->dump_base + nframes;
+  next_frame->op = op;
+  next_frame->args = args;
+  next_frame->envir = sc->envir;
+  next_frame->code = code;
+  sc->dump = (pointer)(nframes+1);
+}
+
+static pointer _s_return(scheme *sc, pointer a)
+{
+  int nframes = (int)sc->dump;
+  struct dump_stack_frame *frame;
+
+  sc->value = (a);
+  if (nframes <= 0) {
+    return sc->NIL;
+  }
+  nframes--;
+  frame = (struct dump_stack_frame *)sc->dump_base + nframes;
+  sc->op = frame->op;
+  sc->args = frame->args;
+  sc->envir = frame->envir;
+  sc->code = frame->code;
+  sc->dump = (pointer)nframes;
+  return sc->T;
+}
+
+static INLINE void dump_stack_reset(scheme *sc)
+{
+  /* in this implementation, sc->dump is the number of frames on the stack */
+  sc->dump = (pointer)0;
+}
+
+static INLINE void dump_stack_initialize(scheme *sc)
+{
+  sc->dump_size = 0;
+  sc->dump_base = NULL;
+  dump_stack_reset(sc);
+}
+
+static void dump_stack_free(scheme *sc)
+{
+  free(sc->dump_base);
+  sc->dump_base = NULL;
+  sc->dump = (pointer)0;
+  sc->dump_size = 0;
+}
+
+static INLINE void dump_stack_mark(scheme *sc)
+{
+  int nframes = (int)sc->dump;
+  int i;
+  for(i=0; i<nframes; i++) {
+    struct dump_stack_frame *frame;
+    frame = (struct dump_stack_frame *)sc->dump_base + i;
+    mark(frame->args);
+    mark(frame->envir);
+    mark(frame->code);
+  }
+}
+
+#else
+
+static INLINE void dump_stack_reset(scheme *sc)
+{
+  sc->dump = sc->NIL;
+}
+
+static INLINE void dump_stack_initialize(scheme *sc)
+{
+  dump_stack_reset(sc);
+}
+
+static void dump_stack_free(scheme *sc)
+{
+  sc->dump = sc->NIL;
+}
+
+static pointer _s_return(scheme *sc, pointer a) {
+    sc->value = (a);
+    if(sc->dump==sc->NIL) return sc->NIL;
+    sc->op = ivalue(car(sc->dump));
+    sc->args = cadr(sc->dump);
+    sc->envir = caddr(sc->dump);
+    sc->code = cadddr(sc->dump);
+    sc->dump = cddddr(sc->dump);
+    return sc->T;
+}
+
+static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
+    sc->dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
+    sc->dump = cons(sc, (args), sc->dump);
+    sc->dump = cons(sc, mk_integer(sc, (long)(op)), sc->dump);
+}
+
+static INLINE void dump_stack_mark(scheme *sc)
+{
+  mark(sc->dump);
+}
+#endif
+
+#define s_retbool(tf)    s_return(sc,(tf) ? sc->T : sc->F)
+
+static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
+     pointer x, y;
+
+     switch (op) {
+     case OP_LOAD:       /* load */
+          if(file_interactive(sc)) {
+               fprintf(sc->outport->_object._port->rep.stdio.file,
+               "Loading %s\n", strvalue(car(sc->args)));
+          }
+          if (!file_push(sc,strvalue(car(sc->args)))) {
+               Error_1(sc,"unable to open", car(sc->args));
+          }
+      else
+        {
+          sc->args = mk_integer(sc,sc->file_i);
+          s_goto(sc,OP_T0LVL);
+        }
+
+     case OP_T0LVL: /* top level */
+       /* If we reached the end of file, this loop is done. */
+       if(sc->loadport->_object._port->kind & port_saw_EOF)
+     {
+       if(sc->file_i == 0)
+         {
+           sc->args=sc->NIL;
+           s_goto(sc,OP_QUIT);
+         }
+       else
+         {
+           file_pop(sc);
+           s_return(sc,sc->value);
+         }
+       /* NOTREACHED */
+     }
+
+       /* If interactive, be nice to user. */
+       if(file_interactive(sc))
+     {
+       sc->envir = sc->global_env;
+       dump_stack_reset(sc);
+       putstr(sc,"\n");
+       putstr(sc,prompt);
+     }
+
+       /* Set up another iteration of REPL */
+       sc->nesting=0;
+       sc->save_inport=sc->inport;
+       sc->inport = sc->loadport;
+       s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
+       s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
+       s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
+       s_goto(sc,OP_READ_INTERNAL);
+
+     case OP_T1LVL: /* top level */
+          sc->code = sc->value;
+          sc->inport=sc->save_inport;
+          s_goto(sc,OP_EVAL);
+
+     case OP_READ_INTERNAL:       /* internal read */
+          sc->tok = token(sc);
+          if(sc->tok==TOK_EOF)
+        { s_return(sc,sc->EOF_OBJ); }
+          s_goto(sc,OP_RDSEXPR);
+
+     case OP_GENSYM:
+          s_return(sc, gensym(sc));
+
+     case OP_VALUEPRINT: /* print evaluation result */
+          /* OP_VALUEPRINT is always pushed, because when changing from
+             non-interactive to interactive mode, it needs to be
+             already on the stack */
+       if(sc->tracing) {
+         putstr(sc,"\nGives: ");
+       }
+       if(file_interactive(sc)) {
+         sc->print_flag = 1;
+         sc->args = sc->value;
+         s_goto(sc,OP_P0LIST);
+       } else {
+         s_return(sc,sc->value);
+       }
+
+     case OP_EVAL:       /* main part of evaluation */
+#if USE_TRACING
+       if(sc->tracing) {
+         /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
+         s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
+         sc->args=sc->code;
+         putstr(sc,"\nEval: ");
+         s_goto(sc,OP_P0LIST);
+       }
+       /* fall through */
+     case OP_REAL_EVAL:
+#endif
+          if (is_symbol(sc->code)) {    /* symbol */
+               x=find_slot_in_env(sc,sc->envir,sc->code,1);
+               if (x != sc->NIL) {
+                    s_return(sc,slot_value_in_env(x));
+               } else {
+                    Error_1(sc,"eval: unbound variable:", sc->code);
+               }
+          } else if (is_pair(sc->code)) {
+               if (is_syntax(x = car(sc->code))) {     /* SYNTAX */
+                    sc->code = cdr(sc->code);
+                    s_goto(sc,syntaxnum(x));
+               } else {/* first, eval top element and eval arguments */
+                    s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
+                    /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
+                    sc->code = car(sc->code);
+                    s_goto(sc,OP_EVAL);
+               }
+          } else {
+               s_return(sc,sc->code);
+          }
+
+     case OP_E0ARGS:     /* eval arguments */
+          if (is_macro(sc->value)) {    /* macro expansion */
+               s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
+               sc->args = cons(sc,sc->code, sc->NIL);
+               sc->code = sc->value;
+               s_goto(sc,OP_APPLY);
+          } else {
+               sc->code = cdr(sc->code);
+               s_goto(sc,OP_E1ARGS);
+          }
+
+     case OP_E1ARGS:     /* eval arguments */
+          sc->args = cons(sc, sc->value, sc->args);
+          if (is_pair(sc->code)) { /* continue */
+               s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
+               sc->code = car(sc->code);
+               sc->args = sc->NIL;
+               s_goto(sc,OP_EVAL);
+          } else {  /* end */
+               sc->args = reverse_in_place(sc, sc->NIL, sc->args);
+               sc->code = car(sc->args);
+               sc->args = cdr(sc->args);
+               s_goto(sc,OP_APPLY);
+          }
+
+#if USE_TRACING
+     case OP_TRACING: {
+       int tr=sc->tracing;
+       sc->tracing=ivalue(car(sc->args));
+       s_return(sc,mk_integer(sc,tr));
+     }
+#endif
+
+     case OP_APPLY:      /* apply 'code' to 'args' */
+#if USE_TRACING
+       if(sc->tracing) {
+         s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
+         sc->print_flag = 1;
+         /*  sc->args=cons(sc,sc->code,sc->args);*/
+         putstr(sc,"\nApply to: ");
+         s_goto(sc,OP_P0LIST);
+       }
+       /* fall through */
+     case OP_REAL_APPLY:
+#endif
+          if (is_proc(sc->code)) {
+               s_goto(sc,procnum(sc->code));   /* PROCEDURE */
+          } else if (is_foreign(sc->code))
+            {
+              /* Keep nested calls from GC'ing the arglist */
+              push_recent_alloc(sc,sc->args,sc->NIL);
+               x=sc->code->_object._ff(sc,sc->args);
+               s_return(sc,x);
+          } else if (is_closure(sc->code) || is_macro(sc->code)
+             || is_promise(sc->code)) { /* CLOSURE */
+        /* Should not accept promise */
+               /* make environment */
+               new_frame_in_env(sc, closure_env(sc->code));
+               for (x = car(closure_code(sc->code)), y = sc->args;
+                    is_pair(x); x = cdr(x), y = cdr(y)) {
+                    if (y == sc->NIL) {
+                         Error_0(sc,"not enough arguments");
+                    } else {
+                         new_slot_in_env(sc, car(x), car(y));
+                    }
+               }
+               if (x == sc->NIL) {
+                    /*--
+                     * if (y != sc->NIL) {
+                     *   Error_0(sc,"too many arguments");
+                     * }
+                     */
+               } else if (is_symbol(x))
+                    new_slot_in_env(sc, x, y);
+               else {
+                    Error_1(sc,"syntax error in closure: not a symbol:", x);
+               }
+               sc->code = cdr(closure_code(sc->code));
+               sc->args = sc->NIL;
+               s_goto(sc,OP_BEGIN);
+          } else if (is_continuation(sc->code)) { /* CONTINUATION */
+               sc->dump = cont_dump(sc->code);
+               s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
+          } else {
+               Error_1(sc,"illegal function",sc->code);
+          }
+
+     case OP_DOMACRO:    /* do macro */
+          sc->code = sc->value;
+          s_goto(sc,OP_EVAL);
+
+#if 1
+     case OP_LAMBDA:     /* lambda */
+          /* If the hook is defined, apply it to sc->code, otherwise
+             set sc->value fall thru */
+          {
+               pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
+               if(f==sc->NIL) {
+                    sc->value = sc->code;
+                    /* Fallthru */
+               } else {
+                    s_save(sc,OP_LAMBDA1,sc->args,sc->code);
+                    sc->args=cons(sc,sc->code,sc->NIL);
+                    sc->code=slot_value_in_env(f);
+                    s_goto(sc,OP_APPLY);
+               }
+          }
+
+     case OP_LAMBDA1:
+          s_return(sc,mk_closure(sc, sc->value, sc->envir));
+
+#else
+     case OP_LAMBDA:     /* lambda */
+          s_return(sc,mk_closure(sc, sc->code, sc->envir));
+
+#endif
+
+     case OP_MKCLOSURE: /* make-closure */
+       x=car(sc->args);
+       if(car(x)==sc->LAMBDA) {
+         x=cdr(x);
+       }
+       if(cdr(sc->args)==sc->NIL) {
+         y=sc->envir;
+       } else {
+         y=cadr(sc->args);
+       }
+       s_return(sc,mk_closure(sc, x, y));
+
+     case OP_QUOTE:      /* quote */
+          s_return(sc,car(sc->code));
+
+     case OP_DEF0:  /* define */
+          if(is_immutable(car(sc->code)))
+            Error_1(sc,"define: unable to alter immutable", car(sc->code));
+
+          if (is_pair(car(sc->code))) {
+               x = caar(sc->code);
+               sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
+          } else {
+               x = car(sc->code);
+               sc->code = cadr(sc->code);
+          }
+          if (!is_symbol(x)) {
+               Error_0(sc,"variable is not a symbol");
+          }
+          s_save(sc,OP_DEF1, sc->NIL, x);
+          s_goto(sc,OP_EVAL);
+
+     case OP_DEF1:  /* define */
+          x=find_slot_in_env(sc,sc->envir,sc->code,0);
+          if (x != sc->NIL) {
+               set_slot_in_env(sc, x, sc->value);
+          } else {
+               new_slot_in_env(sc, sc->code, sc->value);
+          }
+          s_return(sc,sc->code);
+
+
+     case OP_DEFP:  /* defined? */
+          x=sc->envir;
+          if(cdr(sc->args)!=sc->NIL) {
+               x=cadr(sc->args);
+          }
+          s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
+
+     case OP_SET0:       /* set! */
+          if(is_immutable(car(sc->code)))
+                Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
+          s_save(sc,OP_SET1, sc->NIL, car(sc->code));
+          sc->code = cadr(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_SET1:       /* set! */
+          y=find_slot_in_env(sc,sc->envir,sc->code,1);
+          if (y != sc->NIL) {
+               set_slot_in_env(sc, y, sc->value);
+               s_return(sc,sc->value);
+          } else {
+               Error_1(sc,"set!: unbound variable:", sc->code);
+          }
+
+
+     case OP_BEGIN:      /* begin */
+          if (!is_pair(sc->code)) {
+               s_return(sc,sc->code);
+          }
+          if (cdr(sc->code) != sc->NIL) {
+               s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
+          }
+          sc->code = car(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_IF0:        /* if */
+          s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
+          sc->code = car(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_IF1:        /* if */
+          if (is_true(sc->value))
+               sc->code = car(sc->code);
+          else
+               sc->code = cadr(sc->code);  /* (if #f 1) ==> () because
+                                            * car(sc->NIL) = sc->NIL */
+          s_goto(sc,OP_EVAL);
+
+     case OP_LET0:       /* let */
+          sc->args = sc->NIL;
+          sc->value = sc->code;
+          sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
+          s_goto(sc,OP_LET1);
+
+     case OP_LET1:       /* let (calculate parameters) */
+          sc->args = cons(sc, sc->value, sc->args);
+          if (is_pair(sc->code)) { /* continue */
+               if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
+                    Error_1(sc, "Bad syntax of binding spec in let :",
+                            car(sc->code));
+               }
+               s_save(sc,OP_LET1, sc->args, cdr(sc->code));
+               sc->code = cadar(sc->code);
+               sc->args = sc->NIL;
+               s_goto(sc,OP_EVAL);
+          } else {  /* end */
+               sc->args = reverse_in_place(sc, sc->NIL, sc->args);
+               sc->code = car(sc->args);
+               sc->args = cdr(sc->args);
+               s_goto(sc,OP_LET2);
+          }
+
+     case OP_LET2:       /* let */
+          new_frame_in_env(sc, sc->envir);
+          for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
+               y != sc->NIL; x = cdr(x), y = cdr(y)) {
+               new_slot_in_env(sc, caar(x), car(y));
+          }
+          if (is_symbol(car(sc->code))) {    /* named let */
+               for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
+                    if (!is_pair(x))
+                        Error_1(sc, "Bad syntax of binding in let :", x);
+                    if (!is_list(sc, car(x)))
+                        Error_1(sc, "Bad syntax of binding in let :", car(x));
+                    sc->args = cons(sc, caar(x), sc->args);
+               }
+               x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
+               new_slot_in_env(sc, car(sc->code), x);
+               sc->code = cddr(sc->code);
+               sc->args = sc->NIL;
+          } else {
+               sc->code = cdr(sc->code);
+               sc->args = sc->NIL;
+          }
+          s_goto(sc,OP_BEGIN);
+
+     case OP_LET0AST:    /* let* */
+          if (car(sc->code) == sc->NIL) {
+               new_frame_in_env(sc, sc->envir);
+               sc->code = cdr(sc->code);
+               s_goto(sc,OP_BEGIN);
+          }
+          if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
+               Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
+          }
+          s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
+          sc->code = cadaar(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_LET1AST:    /* let* (make new frame) */
+          new_frame_in_env(sc, sc->envir);
+          s_goto(sc,OP_LET2AST);
+
+     case OP_LET2AST:    /* let* (calculate parameters) */
+          new_slot_in_env(sc, caar(sc->code), sc->value);
+          sc->code = cdr(sc->code);
+          if (is_pair(sc->code)) { /* continue */
+               s_save(sc,OP_LET2AST, sc->args, sc->code);
+               sc->code = cadar(sc->code);
+               sc->args = sc->NIL;
+               s_goto(sc,OP_EVAL);
+          } else {  /* end */
+               sc->code = sc->args;
+               sc->args = sc->NIL;
+               s_goto(sc,OP_BEGIN);
+          }
+     default:
+          snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+          Error_0(sc,sc->strbuff);
+     }
+     return sc->T;
+}
+
+static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
+     pointer x, y;
+
+     switch (op) {
+     case OP_LET0REC:    /* letrec */
+          new_frame_in_env(sc, sc->envir);
+          sc->args = sc->NIL;
+          sc->value = sc->code;
+          sc->code = car(sc->code);
+          s_goto(sc,OP_LET1REC);
+
+     case OP_LET1REC:    /* letrec (calculate parameters) */
+          sc->args = cons(sc, sc->value, sc->args);
+          if (is_pair(sc->code)) { /* continue */
+               if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
+                    Error_1(sc, "Bad syntax of binding spec in letrec :",
+                            car(sc->code));
+               }
+               s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
+               sc->code = cadar(sc->code);
+               sc->args = sc->NIL;
+               s_goto(sc,OP_EVAL);
+          } else {  /* end */
+               sc->args = reverse_in_place(sc, sc->NIL, sc->args);
+               sc->code = car(sc->args);
+               sc->args = cdr(sc->args);
+               s_goto(sc,OP_LET2REC);
+          }
+
+     case OP_LET2REC:    /* letrec */
+          for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
+               new_slot_in_env(sc, caar(x), car(y));
+          }
+          sc->code = cdr(sc->code);
+          sc->args = sc->NIL;
+          s_goto(sc,OP_BEGIN);
+
+     case OP_COND0:      /* cond */
+          if (!is_pair(sc->code)) {
+               Error_0(sc,"syntax error in cond");
+          }
+          s_save(sc,OP_COND1, sc->NIL, sc->code);
+          sc->code = caar(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_COND1:      /* cond */
+          if (is_true(sc->value)) {
+               if ((sc->code = cdar(sc->code)) == sc->NIL) {
+                    s_return(sc,sc->value);
+               }
+               if(!sc->code || car(sc->code)==sc->FEED_TO) {
+                    if(!is_pair(cdr(sc->code))) {
+                         Error_0(sc,"syntax error in cond");
+                    }
+                    x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
+                    sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
+                    s_goto(sc,OP_EVAL);
+               }
+               s_goto(sc,OP_BEGIN);
+          } else {
+               if ((sc->code = cdr(sc->code)) == sc->NIL) {
+                    s_return(sc,sc->NIL);
+               } else {
+                    s_save(sc,OP_COND1, sc->NIL, sc->code);
+                    sc->code = caar(sc->code);
+                    s_goto(sc,OP_EVAL);
+               }
+          }
+
+     case OP_DELAY:      /* delay */
+          x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
+          typeflag(x)=T_PROMISE;
+          s_return(sc,x);
+
+     case OP_AND0:       /* and */
+          if (sc->code == sc->NIL) {
+               s_return(sc,sc->T);
+          }
+          s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
+          sc->code = car(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_AND1:       /* and */
+          if (is_false(sc->value)) {
+               s_return(sc,sc->value);
+          } else if (sc->code == sc->NIL) {
+               s_return(sc,sc->value);
+          } else {
+               s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
+               sc->code = car(sc->code);
+               s_goto(sc,OP_EVAL);
+          }
+
+     case OP_OR0:        /* or */
+          if (sc->code == sc->NIL) {
+               s_return(sc,sc->F);
+          }
+          s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
+          sc->code = car(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_OR1:        /* or */
+          if (is_true(sc->value)) {
+               s_return(sc,sc->value);
+          } else if (sc->code == sc->NIL) {
+               s_return(sc,sc->value);
+          } else {
+               s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
+               sc->code = car(sc->code);
+               s_goto(sc,OP_EVAL);
+          }
+
+     case OP_C0STREAM:   /* cons-stream */
+          s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
+          sc->code = car(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_C1STREAM:   /* cons-stream */
+          sc->args = sc->value;  /* save sc->value to register sc->args for gc */
+          x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
+          typeflag(x)=T_PROMISE;
+          s_return(sc,cons(sc, sc->args, x));
+
+     case OP_MACRO0:     /* macro */
+          if (is_pair(car(sc->code))) {
+               x = caar(sc->code);
+               sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
+          } else {
+               x = car(sc->code);
+               sc->code = cadr(sc->code);
+          }
+          if (!is_symbol(x)) {
+               Error_0(sc,"variable is not a symbol");
+          }
+          s_save(sc,OP_MACRO1, sc->NIL, x);
+          s_goto(sc,OP_EVAL);
+
+     case OP_MACRO1:     /* macro */
+          typeflag(sc->value) = T_MACRO;
+          x = find_slot_in_env(sc, sc->envir, sc->code, 0);
+          if (x != sc->NIL) {
+               set_slot_in_env(sc, x, sc->value);
+          } else {
+               new_slot_in_env(sc, sc->code, sc->value);
+          }
+          s_return(sc,sc->code);
+
+     case OP_CASE0:      /* case */
+          s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
+          sc->code = car(sc->code);
+          s_goto(sc,OP_EVAL);
+
+     case OP_CASE1:      /* case */
+          for (x = sc->code; x != sc->NIL; x = cdr(x)) {
+               if (!is_pair(y = caar(x))) {
+                    break;
+               }
+               for ( ; y != sc->NIL; y = cdr(y)) {
+                    if (eqv(car(y), sc->value)) {
+                         break;
+                    }
+               }
+               if (y != sc->NIL) {
+                    break;
+               }
+          }
+          if (x != sc->NIL) {
+               if (is_pair(caar(x))) {
+                    sc->code = cdar(x);
+                    s_goto(sc,OP_BEGIN);
+               } else {/* else */
+                    s_save(sc,OP_CASE2, sc->NIL, cdar(x));
+                    sc->code = caar(x);
+                    s_goto(sc,OP_EVAL);
+               }
+          } else {
+               s_return(sc,sc->NIL);
+          }
+
+     case OP_CASE2:      /* case */
+          if (is_true(sc->value)) {
+               s_goto(sc,OP_BEGIN);
+          } else {
+               s_return(sc,sc->NIL);
+          }
+
+     case OP_PAPPLY:     /* apply */
+          sc->code = car(sc->args);
+          sc->args = list_star(sc,cdr(sc->args));
+          /*sc->args = cadr(sc->args);*/
+          s_goto(sc,OP_APPLY);
+
+     case OP_PEVAL: /* eval */
+          if(cdr(sc->args)!=sc->NIL) {
+               sc->envir=cadr(sc->args);
+          }
+          sc->code = car(sc->args);
+          s_goto(sc,OP_EVAL);
+
+     case OP_CONTINUATION:    /* call-with-current-continuation */
+          sc->code = car(sc->args);
+          sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
+          s_goto(sc,OP_APPLY);
+
+     default:
+          snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+          Error_0(sc,sc->strbuff);
+     }
+     return sc->T;
+}
+
+static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
+     pointer x;
+     num v;
+#if USE_MATH
+     double dd;
+#endif
+
+     switch (op) {
+#if USE_MATH
+     case OP_INEX2EX:    /* inexact->exact */
+          x=car(sc->args);
+          if(num_is_integer(x)) {
+               s_return(sc,x);
+          } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
+               s_return(sc,mk_integer(sc,ivalue(x)));
+          } else {
+               Error_1(sc,"inexact->exact: not integral:",x);
+          }
+
+     case OP_EXP:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, exp(rvalue(x))));
+
+     case OP_LOG:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, log(rvalue(x))));
+
+     case OP_SIN:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, sin(rvalue(x))));
+
+     case OP_COS:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, cos(rvalue(x))));
+
+     case OP_TAN:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, tan(rvalue(x))));
+
+     case OP_ASIN:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, asin(rvalue(x))));
+
+     case OP_ACOS:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, acos(rvalue(x))));
+
+     case OP_ATAN:
+          x=car(sc->args);
+          if(cdr(sc->args)==sc->NIL) {
+               s_return(sc, mk_real(sc, atan(rvalue(x))));
+          } else {
+               pointer y=cadr(sc->args);
+               s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
+          }
+
+     case OP_SQRT:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, sqrt(rvalue(x))));
+
+     case OP_EXPT: {
+          double result;
+          int real_result=1;
+          pointer y=cadr(sc->args);
+          x=car(sc->args);
+          if (num_is_integer(x) && num_is_integer(y))
+             real_result=0;
+          /* This 'if' is an R5RS compatibility fix. */
+          /* NOTE: Remove this 'if' fix for R6RS.    */
+          if (rvalue(x) == 0 && rvalue(y) < 0) {
+             result = 0.0;
+          } else {
+             result = pow(rvalue(x),rvalue(y));
+          }
+          /* Before returning integer result make sure we can. */
+          /* If the test fails, result is too big for integer. */
+          if (!real_result)
+          {
+            long result_as_long = (long)result;
+            if (result != (double)result_as_long)
+              real_result = 1;
+          }
+          if (real_result) {
+             s_return(sc, mk_real(sc, result));
+          } else {
+             s_return(sc, mk_integer(sc, result));
+          }
+     }
+
+     case OP_FLOOR:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, floor(rvalue(x))));
+
+     case OP_CEILING:
+          x=car(sc->args);
+          s_return(sc, mk_real(sc, ceil(rvalue(x))));
+
+     case OP_TRUNCATE : {
+          double rvalue_of_x ;
+          x=car(sc->args);
+          rvalue_of_x = rvalue(x) ;
+          if (rvalue_of_x > 0) {
+            s_return(sc, mk_real(sc, floor(rvalue_of_x)));
+          } else {
+            s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
+          }
+     }
+
+     case OP_ROUND:
+        x=car(sc->args);
+        if (num_is_integer(x))
+            s_return(sc, x);
+        s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
+#endif
+
+     case OP_ADD:        /* + */
+       v=num_zero;
+       for (x = sc->args; x != sc->NIL; x = cdr(x)) {
+         v=num_add(v,nvalue(car(x)));
+       }
+       s_return(sc,mk_number(sc, v));
+
+     case OP_MUL:        /* * */
+       v=num_one;
+       for (x = sc->args; x != sc->NIL; x = cdr(x)) {
+         v=num_mul(v,nvalue(car(x)));
+       }
+       s_return(sc,mk_number(sc, v));
+
+     case OP_SUB:        /* - */
+       if(cdr(sc->args)==sc->NIL) {
+         x=sc->args;
+         v=num_zero;
+       } else {
+         x = cdr(sc->args);
+         v = nvalue(car(sc->args));
+       }
+       for (; x != sc->NIL; x = cdr(x)) {
+         v=num_sub(v,nvalue(car(x)));
+       }
+       s_return(sc,mk_number(sc, v));
+
+     case OP_DIV:        /* / */
+       if(cdr(sc->args)==sc->NIL) {
+         x=sc->args;
+         v=num_one;
+       } else {
+         x = cdr(sc->args);
+         v = nvalue(car(sc->args));
+       }
+       for (; x != sc->NIL; x = cdr(x)) {
+         if (!is_zero_double(rvalue(car(x))))
+           v=num_div(v,nvalue(car(x)));
+         else {
+           Error_0(sc,"/: division by zero");
+         }
+       }
+       s_return(sc,mk_number(sc, v));
+
+     case OP_INTDIV:        /* quotient */
+          if(cdr(sc->args)==sc->NIL) {
+               x=sc->args;
+               v=num_one;
+          } else {
+               x = cdr(sc->args);
+               v = nvalue(car(sc->args));
+          }
+          for (; x != sc->NIL; x = cdr(x)) {
+               if (ivalue(car(x)) != 0)
+                    v=num_intdiv(v,nvalue(car(x)));
+               else {
+                    Error_0(sc,"quotient: division by zero");
+               }
+          }
+          s_return(sc,mk_number(sc, v));
+
+     case OP_REM:        /* remainder */
+          v = nvalue(car(sc->args));
+          if (ivalue(cadr(sc->args)) != 0)
+               v=num_rem(v,nvalue(cadr(sc->args)));
+          else {
+               Error_0(sc,"remainder: division by zero");
+          }
+          s_return(sc,mk_number(sc, v));
+
+     case OP_MOD:        /* modulo */
+          v = nvalue(car(sc->args));
+          if (ivalue(cadr(sc->args)) != 0)
+               v=num_mod(v,nvalue(cadr(sc->args)));
+          else {
+               Error_0(sc,"modulo: division by zero");
+          }
+          s_return(sc,mk_number(sc, v));
+
+     case OP_CAR:        /* car */
+          s_return(sc,caar(sc->args));
+
+     case OP_CDR:        /* cdr */
+          s_return(sc,cdar(sc->args));
+
+     case OP_CONS:       /* cons */
+          cdr(sc->args) = cadr(sc->args);
+          s_return(sc,sc->args);
+
+     case OP_SETCAR:     /* set-car! */
+       if(!is_immutable(car(sc->args))) {
+         caar(sc->args) = cadr(sc->args);
+         s_return(sc,car(sc->args));
+       } else {
+         Error_0(sc,"set-car!: unable to alter immutable pair");
+       }
+
+     case OP_SETCDR:     /* set-cdr! */
+       if(!is_immutable(car(sc->args))) {
+         cdar(sc->args) = cadr(sc->args);
+         s_return(sc,car(sc->args));
+       } else {
+         Error_0(sc,"set-cdr!: unable to alter immutable pair");
+       }
+
+     case OP_CHAR2INT: { /* char->integer */
+          char c;
+          c=(char)ivalue(car(sc->args));
+          s_return(sc,mk_integer(sc,(unsigned char)c));
+     }
+
+     case OP_INT2CHAR: { /* integer->char */
+          unsigned char c;
+          c=(unsigned char)ivalue(car(sc->args));
+          s_return(sc,mk_character(sc,(char)c));
+     }
+
+     case OP_CHARUPCASE: {
+          unsigned char c;
+          c=(unsigned char)ivalue(car(sc->args));
+          c=toupper(c);
+          s_return(sc,mk_character(sc,(char)c));
+     }
+
+     case OP_CHARDNCASE: {
+          unsigned char c;
+          c=(unsigned char)ivalue(car(sc->args));
+          c=tolower(c);
+          s_return(sc,mk_character(sc,(char)c));
+     }
+
+     case OP_STR2SYM:  /* string->symbol */
+          s_return(sc,mk_symbol(sc,strvalue(car(sc->args))));
+
+     case OP_STR2ATOM: /* string->atom */ {
+          char *s=strvalue(car(sc->args));
+          long pf = 0;
+          if(cdr(sc->args)!=sc->NIL) {
+            /* we know cadr(sc->args) is a natural number */
+            /* see if it is 2, 8, 10, or 16, or error */
+            pf = ivalue_unchecked(cadr(sc->args));
+            if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
+               /* base is OK */
+            }
+            else {
+              pf = -1;
+            }
+          }
+          if (pf < 0) {
+            Error_1(sc, "string->atom: bad base:", cadr(sc->args));
+          } else if(*s=='#') /* no use of base! */ {
+            s_return(sc, mk_sharp_const(sc, s+1));
+          } else {
+            if (pf == 0 || pf == 10) {
+              s_return(sc, mk_atom(sc, s));
+            }
+            else {
+              char *ep;
+              long iv = strtol(s,&ep,(int )pf);
+              if (*ep == 0) {
+                s_return(sc, mk_integer(sc, iv));
+              }
+              else {
+                s_return(sc, sc->F);
+              }
+            }
+          }
+        }
+
+     case OP_SYM2STR: /* symbol->string */
+          x=mk_string(sc,symname(car(sc->args)));
+          setimmutable(x);
+          s_return(sc,x);
+
+     case OP_ATOM2STR: /* atom->string */ {
+          long pf = 0;
+          x=car(sc->args);
+          if(cdr(sc->args)!=sc->NIL) {
+            /* we know cadr(sc->args) is a natural number */
+            /* see if it is 2, 8, 10, or 16, or error */
+            pf = ivalue_unchecked(cadr(sc->args));
+            if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
+              /* base is OK */
+            }
+            else {
+              pf = -1;
+            }
+          }
+          if (pf < 0) {
+            Error_1(sc, "atom->string: bad base:", cadr(sc->args));
+          } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
+            char *p;
+            int len;
+            atom2str(sc,x,(int )pf,&p,&len);
+            s_return(sc,mk_counted_string(sc,p,len));
+          } else {
+            Error_1(sc, "atom->string: not an atom:", x);
+          }
+        }
+
+     case OP_MKSTRING: { /* make-string */
+          int fill=' ';
+          int len;
+
+          len=ivalue(car(sc->args));
+
+          if(cdr(sc->args)!=sc->NIL) {
+               fill=charvalue(cadr(sc->args));
+          }
+          s_return(sc,mk_empty_string(sc,len,(char)fill));
+     }
+
+     case OP_STRLEN:  /* string-length */
+          s_return(sc,mk_integer(sc,strlength(car(sc->args))));
+
+     case OP_STRREF: { /* string-ref */
+          char *str;
+          int index;
+
+          str=strvalue(car(sc->args));
+
+          index=ivalue(cadr(sc->args));
+
+          if(index>=strlength(car(sc->args))) {
+               Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
+          }
+
+          s_return(sc,mk_character(sc,((unsigned char*)str)[index]));
+     }
+
+     case OP_STRSET: { /* string-set! */
+          char *str;
+          int index;
+          int c;
+
+          if(is_immutable(car(sc->args))) {
+               Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
+          }
+          str=strvalue(car(sc->args));
+
+          index=ivalue(cadr(sc->args));
+          if(index>=strlength(car(sc->args))) {
+               Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
+          }
+
+          c=charvalue(caddr(sc->args));
+
+          str[index]=(char)c;
+          s_return(sc,car(sc->args));
+     }
+
+     case OP_STRAPPEND: { /* string-append */
+       /* in 1.29 string-append was in Scheme in init.scm but was too slow */
+       int len = 0;
+       pointer newstr;
+       char *pos;
+
+       /* compute needed length for new string */
+       for (x = sc->args; x != sc->NIL; x = cdr(x)) {
+          len += strlength(car(x));
+       }
+       newstr = mk_empty_string(sc, len, ' ');
+       /* store the contents of the argument strings into the new string */
+       for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
+           pos += strlength(car(x)), x = cdr(x)) {
+           memcpy(pos, strvalue(car(x)), strlength(car(x)));
+       }
+       s_return(sc, newstr);
+     }
+
+     case OP_SUBSTR: { /* substring */
+          char *str;
+          int index0;
+          int index1;
+          int len;
+
+          str=strvalue(car(sc->args));
+
+          index0=ivalue(cadr(sc->args));
+
+          if(index0>strlength(car(sc->args))) {
+               Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
+          }
+
+          if(cddr(sc->args)!=sc->NIL) {
+               index1=ivalue(caddr(sc->args));
+               if(index1>strlength(car(sc->args)) || index1<index0) {
+                    Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
+               }
+          } else {
+               index1=strlength(car(sc->args));
+          }
+
+          len=index1-index0;
+          x=mk_empty_string(sc,len,' ');
+          memcpy(strvalue(x),str+index0,len);
+          strvalue(x)[len]=0;
+
+          s_return(sc,x);
+     }
+
+     case OP_VECTOR: {   /* vector */
+          int i;
+          pointer vec;
+          int len=list_length(sc,sc->args);
+          if(len<0) {
+               Error_1(sc,"vector: not a proper list:",sc->args);
+          }
+          vec=mk_vector(sc,len);
+          if(sc->no_memory) { s_return(sc, sc->sink); }
+          for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
+               set_vector_elem(vec,i,car(x));
+          }
+          s_return(sc,vec);
+     }
+
+     case OP_MKVECTOR: { /* make-vector */
+          pointer fill=sc->NIL;
+          int len;
+          pointer vec;
+
+          len=ivalue(car(sc->args));
+
+          if(cdr(sc->args)!=sc->NIL) {
+               fill=cadr(sc->args);
+          }
+          vec=mk_vector(sc,len);
+          if(sc->no_memory) { s_return(sc, sc->sink); }
+          if(fill!=sc->NIL) {
+               fill_vector(vec,fill);
+          }
+          s_return(sc,vec);
+     }
+
+     case OP_VECLEN:  /* vector-length */
+          s_return(sc,mk_integer(sc,ivalue(car(sc->args))));
+
+     case OP_VECREF: { /* vector-ref */
+          int index;
+
+          index=ivalue(cadr(sc->args));
+
+          if(index>=ivalue(car(sc->args))) {
+               Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
+          }
+
+          s_return(sc,vector_elem(car(sc->args),index));
+     }
+
+     case OP_VECSET: {   /* vector-set! */
+          int index;
+
+          if(is_immutable(car(sc->args))) {
+               Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
+          }
+
+          index=ivalue(cadr(sc->args));
+          if(index>=ivalue(car(sc->args))) {
+               Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
+          }
+
+          set_vector_elem(car(sc->args),index,caddr(sc->args));
+          s_return(sc,car(sc->args));
+     }
+
+     default:
+          snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+          Error_0(sc,sc->strbuff);
+     }
+     return sc->T;
+}
+
+static int is_list(scheme *sc, pointer a)
+{ return list_length(sc,a) >= 0; }
+
+/* Result is:
+   proper list: length
+   circular list: -1
+   not even a pair: -2
+   dotted list: -2 minus length before dot
+*/
+int list_length(scheme *sc, pointer a) {
+    int i=0;
+    pointer slow, fast;
+
+    slow = fast = a;
+    while (1)
+    {
+        if (fast == sc->NIL)
+                return i;
+        if (!is_pair(fast))
+                return -2 - i;
+        fast = cdr(fast);
+        ++i;
+        if (fast == sc->NIL)
+                return i;
+        if (!is_pair(fast))
+                return -2 - i;
+        ++i;
+        fast = cdr(fast);
+
+        /* Safe because we would have already returned if `fast'
+           encountered a non-pair. */
+        slow = cdr(slow);
+        if (fast == slow)
+        {
+            /* the fast pointer has looped back around and caught up
+               with the slow pointer, hence the structure is circular,
+               not of finite length, and therefore not a list */
+            return -1;
+        }
+    }
+}
+
+static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
+     pointer x;
+     num v;
+     int (*comp_func)(num,num)=0;
+
+     switch (op) {
+     case OP_NOT:        /* not */
+          s_retbool(is_false(car(sc->args)));
+     case OP_BOOLP:       /* boolean? */
+          s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
+     case OP_EOFOBJP:       /* boolean? */
+          s_retbool(car(sc->args) == sc->EOF_OBJ);
+     case OP_NULLP:       /* null? */
+          s_retbool(car(sc->args) == sc->NIL);
+     case OP_NUMEQ:      /* = */
+     case OP_LESS:       /* < */
+     case OP_GRE:        /* > */
+     case OP_LEQ:        /* <= */
+     case OP_GEQ:        /* >= */
+          switch(op) {
+               case OP_NUMEQ: comp_func=num_eq; break;
+               case OP_LESS:  comp_func=num_lt; break;
+               case OP_GRE:   comp_func=num_gt; break;
+               case OP_LEQ:   comp_func=num_le; break;
+               case OP_GEQ:   comp_func=num_ge; break;
+               default: assert (! "reached");
+          }
+          x=sc->args;
+          v=nvalue(car(x));
+          x=cdr(x);
+
+          for (; x != sc->NIL; x = cdr(x)) {
+               if(!comp_func(v,nvalue(car(x)))) {
+                    s_retbool(0);
+               }
+           v=nvalue(car(x));
+          }
+          s_retbool(1);
+     case OP_SYMBOLP:     /* symbol? */
+          s_retbool(is_symbol(car(sc->args)));
+     case OP_NUMBERP:     /* number? */
+          s_retbool(is_number(car(sc->args)));
+     case OP_STRINGP:     /* string? */
+          s_retbool(is_string(car(sc->args)));
+     case OP_INTEGERP:     /* integer? */
+          s_retbool(is_integer(car(sc->args)));
+     case OP_REALP:     /* real? */
+          s_retbool(is_number(car(sc->args))); /* All numbers are real */
+     case OP_CHARP:     /* char? */
+          s_retbool(is_character(car(sc->args)));
+#if USE_CHAR_CLASSIFIERS
+     case OP_CHARAP:     /* char-alphabetic? */
+          s_retbool(Cisalpha(ivalue(car(sc->args))));
+     case OP_CHARNP:     /* char-numeric? */
+          s_retbool(Cisdigit(ivalue(car(sc->args))));
+     case OP_CHARWP:     /* char-whitespace? */
+          s_retbool(Cisspace(ivalue(car(sc->args))));
+     case OP_CHARUP:     /* char-upper-case? */
+          s_retbool(Cisupper(ivalue(car(sc->args))));
+     case OP_CHARLP:     /* char-lower-case? */
+          s_retbool(Cislower(ivalue(car(sc->args))));
+#endif
+     case OP_PORTP:     /* port? */
+          s_retbool(is_port(car(sc->args)));
+     case OP_INPORTP:     /* input-port? */
+          s_retbool(is_inport(car(sc->args)));
+     case OP_OUTPORTP:     /* output-port? */
+          s_retbool(is_outport(car(sc->args)));
+     case OP_PROCP:       /* procedure? */
+          /*--
+              * continuation should be procedure by the example
+              * (call-with-current-continuation procedure?) ==> #t
+                 * in R^3 report sec. 6.9
+              */
+          s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
+                 || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
+     case OP_PAIRP:       /* pair? */
+          s_retbool(is_pair(car(sc->args)));
+     case OP_LISTP:       /* list? */
+       s_retbool(list_length(sc,car(sc->args)) >= 0);
+
+     case OP_ENVP:        /* environment? */
+          s_retbool(is_environment(car(sc->args)));
+     case OP_VECTORP:     /* vector? */
+          s_retbool(is_vector(car(sc->args)));
+     case OP_EQ:         /* eq? */
+          s_retbool(car(sc->args) == cadr(sc->args));
+     case OP_EQV:        /* eqv? */
+          s_retbool(eqv(car(sc->args), cadr(sc->args)));
+     default:
+          snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+          Error_0(sc,sc->strbuff);
+     }
+     return sc->T;
+}
+
+static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
+     pointer x, y;
+
+     switch (op) {
+     case OP_FORCE:      /* force */
+          sc->code = car(sc->args);
+          if (is_promise(sc->code)) {
+               /* Should change type to closure here */
+               s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
+               sc->args = sc->NIL;
+               s_goto(sc,OP_APPLY);
+          } else {
+               s_return(sc,sc->code);
+          }
+
+     case OP_SAVE_FORCED:     /* Save forced value replacing promise */
+          memcpy(sc->code,sc->value,sizeof(struct cell));
+          s_return(sc,sc->value);
+
+     case OP_WRITE:      /* write */
+     case OP_DISPLAY:    /* display */
+     case OP_WRITE_CHAR: /* write-char */
+          if(is_pair(cdr(sc->args))) {
+               if(cadr(sc->args)!=sc->outport) {
+                    x=cons(sc,sc->outport,sc->NIL);
+                    s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
+                    sc->outport=cadr(sc->args);
+               }
+          }
+          sc->args = car(sc->args);
+          if(op==OP_WRITE) {
+               sc->print_flag = 1;
+          } else {
+               sc->print_flag = 0;
+          }
+          s_goto(sc,OP_P0LIST);
+
+     case OP_NEWLINE:    /* newline */
+          if(is_pair(sc->args)) {
+               if(car(sc->args)!=sc->outport) {
+                    x=cons(sc,sc->outport,sc->NIL);
+                    s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
+                    sc->outport=car(sc->args);
+               }
+          }
+          putstr(sc, "\n");
+          s_return(sc,sc->T);
+
+     case OP_ERR0:  /* error */
+          sc->retcode=-1;
+          if (!is_string(car(sc->args))) {
+               sc->args=cons(sc,mk_string(sc," -- "),sc->args);
+               setimmutable(car(sc->args));
+          }
+          putstr(sc, "Error: ");
+          putstr(sc, strvalue(car(sc->args)));
+          sc->args = cdr(sc->args);
+          s_goto(sc,OP_ERR1);
+
+     case OP_ERR1:  /* error */
+          putstr(sc, " ");
+          if (sc->args != sc->NIL) {
+               s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
+               sc->args = car(sc->args);
+               sc->print_flag = 1;
+               s_goto(sc,OP_P0LIST);
+          } else {
+               putstr(sc, "\n");
+               if(sc->interactive_repl) {
+                    s_goto(sc,OP_T0LVL);
+               } else {
+                    return sc->NIL;
+               }
+          }
+
+     case OP_REVERSE:   /* reverse */
+          s_return(sc,reverse(sc, car(sc->args)));
+
+     case OP_LIST_STAR: /* list* */
+          s_return(sc,list_star(sc,sc->args));
+
+     case OP_APPEND:    /* append */
+          x = sc->NIL;
+          y = sc->args;
+          if (y == x) {
+              s_return(sc, x);
+          }
+
+          /* cdr() in the while condition is not a typo. If car() */
+          /* is used (append '() 'a) will return the wrong result.*/
+          while (cdr(y) != sc->NIL) {
+              x = revappend(sc, x, car(y));
+              y = cdr(y);
+              if (x == sc->F) {
+                  Error_0(sc, "non-list argument to append");
+              }
+          }
+
+          s_return(sc, reverse_in_place(sc, car(y), x));
+
+#if USE_PLIST
+     case OP_PUT:        /* put */
+          if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
+               Error_0(sc,"illegal use of put");
+          }
+          for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
+               if (caar(x) == y) {
+                    break;
+               }
+          }
+          if (x != sc->NIL)
+               cdar(x) = caddr(sc->args);
+          else
+               symprop(car(sc->args)) = cons(sc, cons(sc, y, caddr(sc->args)),
+                                symprop(car(sc->args)));
+          s_return(sc,sc->T);
+
+     case OP_GET:        /* get */
+          if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
+               Error_0(sc,"illegal use of get");
+          }
+          for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
+               if (caar(x) == y) {
+                    break;
+               }
+          }
+          if (x != sc->NIL) {
+               s_return(sc,cdar(x));
+          } else {
+               s_return(sc,sc->NIL);
+          }
+#endif /* USE_PLIST */
+     case OP_QUIT:       /* quit */
+          if(is_pair(sc->args)) {
+               sc->retcode=ivalue(car(sc->args));
+          }
+          return (sc->NIL);
+
+     case OP_GC:         /* gc */
+          gc(sc, sc->NIL, sc->NIL);
+          s_return(sc,sc->T);
+
+     case OP_GCVERB:          /* gc-verbose */
+     {    int  was = sc->gc_verbose;
+
+          sc->gc_verbose = (car(sc->args) != sc->F);
+          s_retbool(was);
+     }
+
+     case OP_NEWSEGMENT: /* new-segment */
+          if (!is_pair(sc->args) || !is_number(car(sc->args))) {
+               Error_0(sc,"new-segment: argument must be a number");
+          }
+          alloc_cellseg(sc, (int) ivalue(car(sc->args)));
+          s_return(sc,sc->T);
+
+     case OP_OBLIST: /* oblist */
+          s_return(sc, oblist_all_symbols(sc));
+
+     case OP_CURR_INPORT: /* current-input-port */
+          s_return(sc,sc->inport);
+
+     case OP_CURR_OUTPORT: /* current-output-port */
+          s_return(sc,sc->outport);
+
+     case OP_OPEN_INFILE: /* open-input-file */
+     case OP_OPEN_OUTFILE: /* open-output-file */
+     case OP_OPEN_INOUTFILE: /* open-input-output-file */ {
+          int prop=0;
+          pointer p;
+          switch(op) {
+               case OP_OPEN_INFILE:     prop=port_input; break;
+               case OP_OPEN_OUTFILE:    prop=port_output; break;
+               case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
+               default: assert (! "reached");
+          }
+          p=port_from_filename(sc,strvalue(car(sc->args)),prop);
+          if(p==sc->NIL) {
+               s_return(sc,sc->F);
+          }
+          s_return(sc,p);
+         break;
+     default: assert (! "reached");
+     }
+
+#if USE_STRING_PORTS
+     case OP_OPEN_INSTRING: /* open-input-string */
+     case OP_OPEN_INOUTSTRING: /* open-input-output-string */ {
+          int prop=0;
+          pointer p;
+          switch(op) {
+               case OP_OPEN_INSTRING:     prop=port_input; break;
+               case OP_OPEN_INOUTSTRING:  prop=port_input|port_output; break;
+               default: assert (! "reached");
+          }
+          p=port_from_string(sc, strvalue(car(sc->args)),
+                 strvalue(car(sc->args))+strlength(car(sc->args)), prop);
+          if(p==sc->NIL) {
+               s_return(sc,sc->F);
+          }
+          s_return(sc,p);
+     }
+     case OP_OPEN_OUTSTRING: /* open-output-string */ {
+          pointer p;
+          if(car(sc->args)==sc->NIL) {
+               p=port_from_scratch(sc);
+               if(p==sc->NIL) {
+                    s_return(sc,sc->F);
+               }
+          } else {
+               p=port_from_string(sc, strvalue(car(sc->args)),
+                      strvalue(car(sc->args))+strlength(car(sc->args)),
+                          port_output);
+               if(p==sc->NIL) {
+                    s_return(sc,sc->F);
+               }
+          }
+          s_return(sc,p);
+     }
+     case OP_GET_OUTSTRING: /* get-output-string */ {
+          port *p;
+
+          if ((p=car(sc->args)->_object._port)->kind&port_string) {
+               off_t size;
+               char *str;
+
+               size=p->rep.string.curr-p->rep.string.start+1;
+               str=sc->malloc(size);
+               if(str != NULL) {
+                    pointer s;
+
+                    memcpy(str,p->rep.string.start,size-1);
+                    str[size-1]='\0';
+                    s=mk_string(sc,str);
+                    sc->free(str);
+                    s_return(sc,s);
+               }
+          }
+          s_return(sc,sc->F);
+     }
+#endif
+
+     case OP_CLOSE_INPORT: /* close-input-port */
+          port_close(sc,car(sc->args),port_input);
+          s_return(sc,sc->T);
+
+     case OP_CLOSE_OUTPORT: /* close-output-port */
+          port_close(sc,car(sc->args),port_output);
+          s_return(sc,sc->T);
+
+     case OP_INT_ENV: /* interaction-environment */
+          s_return(sc,sc->global_env);
+
+     case OP_CURR_ENV: /* current-environment */
+          s_return(sc,sc->envir);
+
+     }
+     return sc->T;
+}
+
+static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
+     pointer x;
+
+     if(sc->nesting!=0) {
+          int n=sc->nesting;
+          sc->nesting=0;
+          sc->retcode=-1;
+          Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
+     }
+
+     switch (op) {
+     /* ========== reading part ========== */
+     case OP_READ:
+          if(!is_pair(sc->args)) {
+               s_goto(sc,OP_READ_INTERNAL);
+          }
+          if(!is_inport(car(sc->args))) {
+               Error_1(sc,"read: not an input port:",car(sc->args));
+          }
+          if(car(sc->args)==sc->inport) {
+               s_goto(sc,OP_READ_INTERNAL);
+          }
+          x=sc->inport;
+          sc->inport=car(sc->args);
+          x=cons(sc,x,sc->NIL);
+          s_save(sc,OP_SET_INPORT, x, sc->NIL);
+          s_goto(sc,OP_READ_INTERNAL);
+
+     case OP_READ_CHAR: /* read-char */
+     case OP_PEEK_CHAR: /* peek-char */ {
+          int c;
+          if(is_pair(sc->args)) {
+               if(car(sc->args)!=sc->inport) {
+                    x=sc->inport;
+                    x=cons(sc,x,sc->NIL);
+                    s_save(sc,OP_SET_INPORT, x, sc->NIL);
+                    sc->inport=car(sc->args);
+               }
+          }
+          c=inchar(sc);
+          if(c==EOF) {
+               s_return(sc,sc->EOF_OBJ);
+          }
+          if(sc->op==OP_PEEK_CHAR) {
+               backchar(sc,c);
+          }
+          s_return(sc,mk_character(sc,c));
+     }
+
+     case OP_CHAR_READY: /* char-ready? */ {
+          pointer p=sc->inport;
+          int res;
+          if(is_pair(sc->args)) {
+               p=car(sc->args);
+          }
+          res=p->_object._port->kind&port_string;
+          s_retbool(res);
+     }
+
+     case OP_SET_INPORT: /* set-input-port */
+          sc->inport=car(sc->args);
+          s_return(sc,sc->value);
+
+     case OP_SET_OUTPORT: /* set-output-port */
+          sc->outport=car(sc->args);
+          s_return(sc,sc->value);
+
+     case OP_RDSEXPR:
+          switch (sc->tok) {
+          case TOK_EOF:
+               s_return(sc,sc->EOF_OBJ);
+          /* NOTREACHED */
+/*
+ * Commented out because we now skip comments in the scanner
+ *
+          case TOK_COMMENT: {
+               int c;
+               while ((c=inchar(sc)) != '\n' && c!=EOF)
+                    ;
+               sc->tok = token(sc);
+               s_goto(sc,OP_RDSEXPR);
+          }
+*/
+          case TOK_VEC:
+               s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
+               /* fall through */
+          case TOK_LPAREN:
+               sc->tok = token(sc);
+               if (sc->tok == TOK_RPAREN) {
+                    s_return(sc,sc->NIL);
+               } else if (sc->tok == TOK_DOT) {
+                    Error_0(sc,"syntax error: illegal dot expression");
+               } else {
+                    sc->nesting_stack[sc->file_i]++;
+                    s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
+                    s_goto(sc,OP_RDSEXPR);
+               }
+          case TOK_QUOTE:
+               s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
+               sc->tok = token(sc);
+               s_goto(sc,OP_RDSEXPR);
+          case TOK_BQUOTE:
+               sc->tok = token(sc);
+               if(sc->tok==TOK_VEC) {
+                 s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
+                 sc->tok=TOK_LPAREN;
+                 s_goto(sc,OP_RDSEXPR);
+               } else {
+                 s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
+               }
+               s_goto(sc,OP_RDSEXPR);
+          case TOK_COMMA:
+               s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
+               sc->tok = token(sc);
+               s_goto(sc,OP_RDSEXPR);
+          case TOK_ATMARK:
+               s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
+               sc->tok = token(sc);
+               s_goto(sc,OP_RDSEXPR);
+          case TOK_ATOM:
+               s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
+          case TOK_DQUOTE:
+               x=readstrexp(sc);
+               if(x==sc->F) {
+                 Error_0(sc,"Error reading string");
+               }
+               setimmutable(x);
+               s_return(sc,x);
+          case TOK_SHARP: {
+               pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
+               if(f==sc->NIL) {
+                    Error_0(sc,"undefined sharp expression");
+               } else {
+                    sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
+                    s_goto(sc,OP_EVAL);
+               }
+          }
+          case TOK_SHARP_CONST:
+               if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
+                    Error_0(sc,"undefined sharp expression");
+               } else {
+                    s_return(sc,x);
+               }
+          default:
+               Error_0(sc,"syntax error: illegal token");
+          }
+          break;
+
+     case OP_RDLIST: {
+          sc->args = cons(sc, sc->value, sc->args);
+          sc->tok = token(sc);
+/* We now skip comments in the scanner
+          while (sc->tok == TOK_COMMENT) {
+               int c;
+               while ((c=inchar(sc)) != '\n' && c!=EOF)
+                    ;
+               sc->tok = token(sc);
+          }
+*/
+          if (sc->tok == TOK_EOF)
+               { s_return(sc,sc->EOF_OBJ); }
+          else if (sc->tok == TOK_RPAREN) {
+               int c = inchar(sc);
+               if (c != '\n')
+                 backchar(sc,c);
+#if SHOW_ERROR_LINE
+               else if (sc->load_stack[sc->file_i].kind & port_file)
+                  sc->load_stack[sc->file_i].rep.stdio.curr_line++;
+#endif
+               sc->nesting_stack[sc->file_i]--;
+               s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
+          } else if (sc->tok == TOK_DOT) {
+               s_save(sc,OP_RDDOT, sc->args, sc->NIL);
+               sc->tok = token(sc);
+               s_goto(sc,OP_RDSEXPR);
+          } else {
+               s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
+               s_goto(sc,OP_RDSEXPR);
+          }
+     }
+
+     case OP_RDDOT:
+          if (token(sc) != TOK_RPAREN) {
+               Error_0(sc,"syntax error: illegal dot expression");
+          } else {
+               sc->nesting_stack[sc->file_i]--;
+               s_return(sc,reverse_in_place(sc, sc->value, sc->args));
+          }
+
+     case OP_RDQUOTE:
+          s_return(sc,cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL)));
+
+     case OP_RDQQUOTE:
+          s_return(sc,cons(sc, sc->QQUOTE, cons(sc, sc->value, sc->NIL)));
+
+     case OP_RDQQUOTEVEC:
+           s_return(sc,cons(sc, mk_symbol(sc,"apply"),
+           cons(sc, mk_symbol(sc,"vector"),
+                 cons(sc,cons(sc, sc->QQUOTE,
+                  cons(sc,sc->value,sc->NIL)),
+                  sc->NIL))));
+
+     case OP_RDUNQUOTE:
+          s_return(sc,cons(sc, sc->UNQUOTE, cons(sc, sc->value, sc->NIL)));
+
+     case OP_RDUQTSP:
+          s_return(sc,cons(sc, sc->UNQUOTESP, cons(sc, sc->value, sc->NIL)));
+
+     case OP_RDVEC:
+          /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
+          s_goto(sc,OP_EVAL); Cannot be quoted*/
+          /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
+          s_return(sc,x); Cannot be part of pairs*/
+          /*sc->code=mk_proc(sc,OP_VECTOR);
+          sc->args=sc->value;
+          s_goto(sc,OP_APPLY);*/
+          sc->args=sc->value;
+          s_goto(sc,OP_VECTOR);
+
+     /* ========== printing part ========== */
+     case OP_P0LIST:
+          if(is_vector(sc->args)) {
+               putstr(sc,"#(");
+               sc->args=cons(sc,sc->args,mk_integer(sc,0));
+               s_goto(sc,OP_PVECFROM);
+          } else if(is_environment(sc->args)) {
+               putstr(sc,"#<ENVIRONMENT>");
+               s_return(sc,sc->T);
+          } else if (!is_pair(sc->args)) {
+               printatom(sc, sc->args, sc->print_flag);
+               s_return(sc,sc->T);
+          } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
+               putstr(sc, "'");
+               sc->args = cadr(sc->args);
+               s_goto(sc,OP_P0LIST);
+          } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
+               putstr(sc, "`");
+               sc->args = cadr(sc->args);
+               s_goto(sc,OP_P0LIST);
+          } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
+               putstr(sc, ",");
+               sc->args = cadr(sc->args);
+               s_goto(sc,OP_P0LIST);
+          } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
+               putstr(sc, ",@");
+               sc->args = cadr(sc->args);
+               s_goto(sc,OP_P0LIST);
+          } else {
+               putstr(sc, "(");
+               s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
+               sc->args = car(sc->args);
+               s_goto(sc,OP_P0LIST);
+          }
+
+     case OP_P1LIST:
+          if (is_pair(sc->args)) {
+            s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
+            putstr(sc, " ");
+            sc->args = car(sc->args);
+            s_goto(sc,OP_P0LIST);
+          } else if(is_vector(sc->args)) {
+            s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
+            putstr(sc, " . ");
+            s_goto(sc,OP_P0LIST);
+          } else {
+            if (sc->args != sc->NIL) {
+              putstr(sc, " . ");
+              printatom(sc, sc->args, sc->print_flag);
+            }
+            putstr(sc, ")");
+            s_return(sc,sc->T);
+          }
+     case OP_PVECFROM: {
+          int i=ivalue_unchecked(cdr(sc->args));
+          pointer vec=car(sc->args);
+          int len=ivalue_unchecked(vec);
+          if(i==len) {
+               putstr(sc,")");
+               s_return(sc,sc->T);
+          } else {
+               pointer elem=vector_elem(vec,i);
+               ivalue_unchecked(cdr(sc->args))=i+1;
+               s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
+               sc->args=elem;
+               if (i > 0)
+                   putstr(sc," ");
+               s_goto(sc,OP_P0LIST);
+          }
+     }
+
+     default:
+          snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+          Error_0(sc,sc->strbuff);
+
+     }
+     return sc->T;
+}
+
+static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
+     pointer x, y;
+     long v;
+
+     switch (op) {
+     case OP_LIST_LENGTH:     /* length */   /* a.k */
+          v=list_length(sc,car(sc->args));
+          if(v<0) {
+               Error_1(sc,"length: not a list:",car(sc->args));
+          }
+          s_return(sc,mk_integer(sc, v));
+
+     case OP_ASSQ:       /* assq */     /* a.k */
+          x = car(sc->args);
+          for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
+               if (!is_pair(car(y))) {
+                    Error_0(sc,"unable to handle non pair element");
+               }
+               if (x == caar(y))
+                    break;
+          }
+          if (is_pair(y)) {
+               s_return(sc,car(y));
+          } else {
+               s_return(sc,sc->F);
+          }
+
+
+     case OP_GET_CLOSURE:     /* get-closure-code */   /* a.k */
+          sc->args = car(sc->args);
+          if (sc->args == sc->NIL) {
+               s_return(sc,sc->F);
+          } else if (is_closure(sc->args)) {
+               s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
+          } else if (is_macro(sc->args)) {
+               s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
+          } else {
+               s_return(sc,sc->F);
+          }
+     case OP_CLOSUREP:        /* closure? */
+          /*
+           * Note, macro object is also a closure.
+           * Therefore, (closure? <#MACRO>) ==> #t
+           */
+          s_retbool(is_closure(car(sc->args)));
+     case OP_MACROP:          /* macro? */
+          s_retbool(is_macro(car(sc->args)));
+     default:
+          snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+          Error_0(sc,sc->strbuff);
+     }
+     return sc->T; /* NOTREACHED */
+}
+
+typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
+
+typedef int (*test_predicate)(pointer);
+
+static int is_any(pointer p) {
+   (void)p;
+   return 1;
+}
+
+static int is_nonneg(pointer p) {
+  return ivalue(p)>=0 && is_integer(p);
+}
+
+/* Correspond carefully with following defines! */
+static struct {
+  test_predicate fct;
+  const char *kind;
+} tests[]={
+  {0,0}, /* unused */
+  {is_any, 0},
+  {is_string, "string"},
+  {is_symbol, "symbol"},
+  {is_port, "port"},
+  {is_inport,"input port"},
+  {is_outport,"output port"},
+  {is_environment, "environment"},
+  {is_pair, "pair"},
+  {0, "pair or '()"},
+  {is_character, "character"},
+  {is_vector, "vector"},
+  {is_number, "number"},
+  {is_integer, "integer"},
+  {is_nonneg, "non-negative integer"}
+};
+
+#define TST_NONE 0
+#define TST_ANY "\001"
+#define TST_STRING "\002"
+#define TST_SYMBOL "\003"
+#define TST_PORT "\004"
+#define TST_INPORT "\005"
+#define TST_OUTPORT "\006"
+#define TST_ENVIRONMENT "\007"
+#define TST_PAIR "\010"
+#define TST_LIST "\011"
+#define TST_CHAR "\012"
+#define TST_VECTOR "\013"
+#define TST_NUMBER "\014"
+#define TST_INTEGER "\015"
+#define TST_NATURAL "\016"
+
+typedef struct {
+  dispatch_func func;
+  char *name;
+  int min_arity;
+  int max_arity;
+  char *arg_tests_encoding;
+} op_code_info;
+
+#define INF_ARG 0xffff
+
+static op_code_info dispatch_table[]= {
+#define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
+#include "opdefines.h"
+  { 0 }
+};
+
+static const char *procname(pointer x) {
+ int n=procnum(x);
+ const char *name=dispatch_table[n].name;
+ if(name==0) {
+     name="ILLEGAL!";
+ }
+ return name;
+}
+
+/* kernel of this interpreter */
+static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
+  sc->op = op;
+  for (;;) {
+    op_code_info *pcd=dispatch_table+sc->op;
+    if (pcd->name!=0) { /* if built-in function, check arguments */
+      char msg[STRBUFFSIZE];
+      int ok=1;
+      int n=list_length(sc,sc->args);
+
+      /* Check number of arguments */
+      if(n<pcd->min_arity) {
+        ok=0;
+        snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
+        pcd->name,
+        pcd->min_arity==pcd->max_arity?"":" at least",
+        pcd->min_arity);
+      }
+      if(ok && n>pcd->max_arity) {
+        ok=0;
+        snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
+        pcd->name,
+        pcd->min_arity==pcd->max_arity?"":" at most",
+        pcd->max_arity);
+      }
+      if(ok) {
+        if(pcd->arg_tests_encoding!=0) {
+          int i=0;
+          int j;
+          const char *t=pcd->arg_tests_encoding;
+          pointer arglist=sc->args;
+          do {
+            pointer arg=car(arglist);
+            j=(int)t[0];
+            if(j==TST_LIST[0]) {
+                  if(arg!=sc->NIL && !is_pair(arg)) break;
+            } else {
+              if(!tests[j].fct(arg)) break;
+            }
+
+            if(t[1]!=0) {/* last test is replicated as necessary */
+              t++;
+            }
+            arglist=cdr(arglist);
+            i++;
+          } while(i<n);
+          if(i<n) {
+            ok=0;
+            snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s, got: %s",
+                pcd->name,
+                i+1,
+               tests[j].kind,
+               type_to_string(type(car(arglist))));
+          }
+        }
+      }
+      if(!ok) {
+        if(_Error_1(sc,msg,0)==sc->NIL) {
+          return;
+        }
+        pcd=dispatch_table+sc->op;
+      }
+    }
+    ok_to_freely_gc(sc);
+    if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
+      return;
+    }
+    if(sc->no_memory) {
+      fprintf(stderr,"No memory!\n");
+      exit(1);
+    }
+  }
+}
+
+/* ========== Initialization of internal keywords ========== */
+
+static void assign_syntax(scheme *sc, char *name) {
+     pointer x;
+
+     x = oblist_add_by_name(sc, name);
+     typeflag(x) |= T_SYNTAX;
+}
+
+static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
+     pointer x, y;
+
+     x = mk_symbol(sc, name);
+     y = mk_proc(sc,op);
+     new_slot_in_env(sc, x, y);
+}
+
+static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
+     pointer y;
+
+     y = get_cell(sc, sc->NIL, sc->NIL);
+     typeflag(y) = (T_PROC | T_ATOM);
+     ivalue_unchecked(y) = (long) op;
+     set_num_integer(y);
+     return y;
+}
+
+/* Hard-coded for the given keywords. Remember to rewrite if more are added! */
+static int syntaxnum(pointer p) {
+     const char *s=strvalue(car(p));
+     switch(strlength(car(p))) {
+     case 2:
+          if(s[0]=='i') return OP_IF0;        /* if */
+          else return OP_OR0;                 /* or */
+     case 3:
+          if(s[0]=='a') return OP_AND0;      /* and */
+          else return OP_LET0;               /* let */
+     case 4:
+          switch(s[3]) {
+          case 'e': return OP_CASE0;         /* case */
+          case 'd': return OP_COND0;         /* cond */
+          case '*': return OP_LET0AST;       /* let* */
+          default: return OP_SET0;           /* set! */
+          }
+     case 5:
+          switch(s[2]) {
+          case 'g': return OP_BEGIN;         /* begin */
+          case 'l': return OP_DELAY;         /* delay */
+          case 'c': return OP_MACRO0;        /* macro */
+          default: return OP_QUOTE;          /* quote */
+          }
+     case 6:
+          switch(s[2]) {
+          case 'm': return OP_LAMBDA;        /* lambda */
+          case 'f': return OP_DEF0;          /* define */
+          default: return OP_LET0REC;        /* letrec */
+          }
+     default:
+          return OP_C0STREAM;                /* cons-stream */
+     }
+}
+
+/* initialization of TinyScheme */
+#if USE_INTERFACE
+INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
+ return cons(sc,a,b);
+}
+INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
+ return immutable_cons(sc,a,b);
+}
+
+static struct scheme_interface vtbl ={
+  scheme_define,
+  s_cons,
+  s_immutable_cons,
+  reserve_cells,
+  mk_integer,
+  mk_real,
+  mk_symbol,
+  gensym,
+  mk_string,
+  mk_counted_string,
+  mk_character,
+  mk_vector,
+  mk_foreign_func,
+  mk_foreign_object,
+  get_foreign_object_vtable,
+  get_foreign_object_data,
+  putstr,
+  putcharacter,
+
+  is_string,
+  string_value,
+  is_number,
+  nvalue,
+  ivalue,
+  rvalue,
+  is_integer,
+  is_real,
+  is_character,
+  charvalue,
+  is_list,
+  is_vector,
+  list_length,
+  ivalue,
+  fill_vector,
+  vector_elem,
+  set_vector_elem,
+  is_port,
+  is_pair,
+  pair_car,
+  pair_cdr,
+  set_car,
+  set_cdr,
+
+  is_symbol,
+  symname,
+
+  is_syntax,
+  is_proc,
+  is_foreign,
+  syntaxname,
+  is_closure,
+  is_macro,
+  closure_code,
+  closure_env,
+
+  is_continuation,
+  is_promise,
+  is_environment,
+  is_immutable,
+  setimmutable,
+
+  scheme_load_file,
+  scheme_load_string,
+  port_from_file
+};
+#endif
+
+scheme *scheme_init_new() {
+  scheme *sc=(scheme*)malloc(sizeof(scheme));
+  if(!scheme_init(sc)) {
+    free(sc);
+    return 0;
+  } else {
+    return sc;
+  }
+}
+
+scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
+  scheme *sc=(scheme*)malloc(sizeof(scheme));
+  if(!scheme_init_custom_alloc(sc,malloc,free)) {
+    free(sc);
+    return 0;
+  } else {
+    return sc;
+  }
+}
+
+
+int scheme_init(scheme *sc) {
+ return scheme_init_custom_alloc(sc,malloc,free);
+}
+
+int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
+  int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
+  pointer x;
+
+  num_zero.is_fixnum=1;
+  num_zero.value.ivalue=0;
+  num_one.is_fixnum=1;
+  num_one.value.ivalue=1;
+
+#if USE_INTERFACE
+  sc->vptr=&vtbl;
+#endif
+  sc->gensym_cnt=0;
+  sc->malloc=malloc;
+  sc->free=free;
+  sc->last_cell_seg = -1;
+  sc->sink = &sc->_sink;
+  sc->NIL = &sc->_NIL;
+  sc->T = &sc->_HASHT;
+  sc->F = &sc->_HASHF;
+  sc->EOF_OBJ=&sc->_EOF_OBJ;
+  sc->free_cell = &sc->_NIL;
+  sc->fcells = 0;
+  sc->no_memory=0;
+  sc->inport=sc->NIL;
+  sc->outport=sc->NIL;
+  sc->save_inport=sc->NIL;
+  sc->loadport=sc->NIL;
+  sc->nesting=0;
+  sc->interactive_repl=0;
+  sc->strbuff = sc->malloc(STRBUFFSIZE);
+  if (sc->strbuff == 0) {
+     sc->no_memory=1;
+     return 0;
+  }
+  sc->strbuff_size = STRBUFFSIZE;
+
+  if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
+    sc->no_memory=1;
+    return 0;
+  }
+  sc->gc_verbose = 0;
+  dump_stack_initialize(sc);
+  sc->code = sc->NIL;
+  sc->tracing=0;
+
+  /* init sc->NIL */
+  typeflag(sc->NIL) = (T_NIL | T_ATOM | MARK);
+  car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
+  /* init T */
+  typeflag(sc->T) = (T_BOOLEAN | T_ATOM | MARK);
+  car(sc->T) = cdr(sc->T) = sc->T;
+  /* init F */
+  typeflag(sc->F) = (T_BOOLEAN | T_ATOM | MARK);
+  car(sc->F) = cdr(sc->F) = sc->F;
+  /* init EOF_OBJ */
+  typeflag(sc->EOF_OBJ) = (T_EOF_OBJ | T_ATOM | MARK);
+  car(sc->EOF_OBJ) = cdr(sc->EOF_OBJ) = sc->EOF_OBJ;
+  /* init sink */
+  typeflag(sc->sink) = (T_SINK | T_PAIR | MARK);
+  car(sc->sink) = sc->NIL;
+  /* init c_nest */
+  sc->c_nest = sc->NIL;
+
+  sc->oblist = oblist_initial_value(sc);
+  /* init global_env */
+  new_frame_in_env(sc, sc->NIL);
+  sc->global_env = sc->envir;
+  /* init else */
+  x = mk_symbol(sc,"else");
+  new_slot_in_env(sc, x, sc->T);
+
+  assign_syntax(sc, "lambda");
+  assign_syntax(sc, "quote");
+  assign_syntax(sc, "define");
+  assign_syntax(sc, "if");
+  assign_syntax(sc, "begin");
+  assign_syntax(sc, "set!");
+  assign_syntax(sc, "let");
+  assign_syntax(sc, "let*");
+  assign_syntax(sc, "letrec");
+  assign_syntax(sc, "cond");
+  assign_syntax(sc, "delay");
+  assign_syntax(sc, "and");
+  assign_syntax(sc, "or");
+  assign_syntax(sc, "cons-stream");
+  assign_syntax(sc, "macro");
+  assign_syntax(sc, "case");
+
+  for(i=0; i<n; i++) {
+    if(dispatch_table[i].name!=0) {
+      assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
+    }
+  }
+
+  /* initialization of global pointers to special symbols */
+  sc->LAMBDA = mk_symbol(sc, "lambda");
+  sc->QUOTE = mk_symbol(sc, "quote");
+  sc->QQUOTE = mk_symbol(sc, "quasiquote");
+  sc->UNQUOTE = mk_symbol(sc, "unquote");
+  sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
+  sc->FEED_TO = mk_symbol(sc, "=>");
+  sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
+  sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
+  sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
+  sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
+
+  return !sc->no_memory;
+}
+
+void scheme_set_input_port_file(scheme *sc, FILE *fin) {
+  sc->inport=port_from_file(sc,fin,port_input);
+}
+
+void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
+  sc->inport=port_from_string(sc,start,past_the_end,port_input);
+}
+
+void scheme_set_output_port_file(scheme *sc, FILE *fout) {
+  sc->outport=port_from_file(sc,fout,port_output);
+}
+
+void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
+  sc->outport=port_from_string(sc,start,past_the_end,port_output);
+}
+
+void scheme_set_external_data(scheme *sc, void *p) {
+ sc->ext_data=p;
+}
+
+void scheme_deinit(scheme *sc) {
+  int i;
+
+#if SHOW_ERROR_LINE
+  char *fname;
+#endif
+
+  sc->oblist=sc->NIL;
+  sc->global_env=sc->NIL;
+  dump_stack_free(sc);
+  sc->envir=sc->NIL;
+  sc->code=sc->NIL;
+  sc->args=sc->NIL;
+  sc->value=sc->NIL;
+  if(is_port(sc->inport)) {
+    typeflag(sc->inport) = T_ATOM;
+  }
+  sc->inport=sc->NIL;
+  sc->outport=sc->NIL;
+  if(is_port(sc->save_inport)) {
+    typeflag(sc->save_inport) = T_ATOM;
+  }
+  sc->save_inport=sc->NIL;
+  if(is_port(sc->loadport)) {
+    typeflag(sc->loadport) = T_ATOM;
+  }
+  sc->loadport=sc->NIL;
+  sc->gc_verbose=0;
+  gc(sc,sc->NIL,sc->NIL);
+
+  for(i=0; i<=sc->last_cell_seg; i++) {
+    sc->free(sc->alloc_seg[i]);
+  }
+  sc->free(sc->strbuff);
+
+#if SHOW_ERROR_LINE
+  for(i=0; i<=sc->file_i; i++) {
+    if (sc->load_stack[i].kind & port_file) {
+      fname = sc->load_stack[i].rep.stdio.filename;
+      if(fname)
+        sc->free(fname);
+    }
+  }
+#endif
+}
+
+void scheme_load_file(scheme *sc, FILE *fin)
+{ scheme_load_named_file(sc,fin,0); }
+
+void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
+  dump_stack_reset(sc);
+  sc->envir = sc->global_env;
+  sc->file_i=0;
+  sc->load_stack[0].kind=port_input|port_file;
+  sc->load_stack[0].rep.stdio.file=fin;
+  sc->loadport=mk_port(sc,sc->load_stack);
+  sc->retcode=0;
+  if(fin==stdin) {
+    sc->interactive_repl=1;
+  }
+
+#if SHOW_ERROR_LINE
+  sc->load_stack[0].rep.stdio.curr_line = 0;
+  if(fin!=stdin && filename)
+    sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0);
+  else
+    sc->load_stack[0].rep.stdio.filename = NULL;
+#endif
+
+  sc->inport=sc->loadport;
+  sc->args = mk_integer(sc,sc->file_i);
+  Eval_Cycle(sc, OP_T0LVL);
+  typeflag(sc->loadport)=T_ATOM;
+  if(sc->retcode==0) {
+    sc->retcode=sc->nesting!=0;
+  }
+
+#if SHOW_ERROR_LINE
+  sc->free(sc->load_stack[0].rep.stdio.filename);
+  sc->load_stack[0].rep.stdio.filename = NULL;
+#endif
+}
+
+void scheme_load_string(scheme *sc, const char *cmd) {
+  dump_stack_reset(sc);
+  sc->envir = sc->global_env;
+  sc->file_i=0;
+  sc->load_stack[0].kind=port_input|port_string;
+  sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
+  sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
+  sc->load_stack[0].rep.string.curr=(char*)cmd;
+  sc->loadport=mk_port(sc,sc->load_stack);
+  sc->retcode=0;
+  sc->interactive_repl=0;
+  sc->inport=sc->loadport;
+  sc->args = mk_integer(sc,sc->file_i);
+  Eval_Cycle(sc, OP_T0LVL);
+  typeflag(sc->loadport)=T_ATOM;
+  if(sc->retcode==0) {
+    sc->retcode=sc->nesting!=0;
+  }
+}
+
+void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
+     pointer x;
+
+     x=find_slot_in_env(sc,envir,symbol,0);
+     if (x != sc->NIL) {
+          set_slot_in_env(sc, x, value);
+     } else {
+          new_slot_spec_in_env(sc, envir, symbol, value);
+     }
+}
+
+#if !STANDALONE
+void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
+{
+  scheme_define(sc,
+                sc->global_env,
+                mk_symbol(sc,sr->name),
+                mk_foreign_func(sc, sr->f));
+}
+
+void scheme_register_foreign_func_list(scheme * sc,
+                                       scheme_registerable * list,
+                                       int count)
+{
+  int i;
+  for(i = 0; i < count; i++)
+    {
+      scheme_register_foreign_func(sc, list + i);
+    }
+}
+
+pointer scheme_apply0(scheme *sc, const char *procname)
+{ return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
+
+void save_from_C_call(scheme *sc)
+{
+  pointer saved_data =
+    cons(sc,
+         car(sc->sink),
+         cons(sc,
+              sc->envir,
+              sc->dump));
+  /* Push */
+  sc->c_nest = cons(sc, saved_data, sc->c_nest);
+  /* Truncate the dump stack so TS will return here when done, not
+     directly resume pre-C-call operations. */
+  dump_stack_reset(sc);
+}
+void restore_from_C_call(scheme *sc)
+{
+  car(sc->sink) = caar(sc->c_nest);
+  sc->envir = cadar(sc->c_nest);
+  sc->dump = cdr(cdar(sc->c_nest));
+  /* Pop */
+  sc->c_nest = cdr(sc->c_nest);
+}
+
+/* "func" and "args" are assumed to be already eval'ed. */
+pointer scheme_call(scheme *sc, pointer func, pointer args)
+{
+  int old_repl = sc->interactive_repl;
+  sc->interactive_repl = 0;
+  save_from_C_call(sc);
+  sc->envir = sc->global_env;
+  sc->args = args;
+  sc->code = func;
+  sc->retcode = 0;
+  Eval_Cycle(sc, OP_APPLY);
+  sc->interactive_repl = old_repl;
+  restore_from_C_call(sc);
+  return sc->value;
+}
+
+pointer scheme_eval(scheme *sc, pointer obj)
+{
+  int old_repl = sc->interactive_repl;
+  sc->interactive_repl = 0;
+  save_from_C_call(sc);
+  sc->args = sc->NIL;
+  sc->code = obj;
+  sc->retcode = 0;
+  Eval_Cycle(sc, OP_EVAL);
+  sc->interactive_repl = old_repl;
+  restore_from_C_call(sc);
+  return sc->value;
+}
+
+
+#endif
+
+/* ========== Main ========== */
+
+#if STANDALONE
+
+#if defined(__APPLE__) && !defined (OSX)
+int main()
+{
+     extern MacTS_main(int argc, char **argv);
+     char**    argv;
+     int argc = ccommand(&argv);
+     MacTS_main(argc,argv);
+     return 0;
+}
+int MacTS_main(int argc, char **argv) {
+#else
+int main(int argc, char **argv) {
+#endif
+  scheme sc;
+  FILE *fin;
+  char *file_name=InitFile;
+  int retcode;
+  int isfile=1;
+
+  if(argc==1) {
+    printf(banner);
+  }
+  if(argc==2 && strcmp(argv[1],"-?")==0) {
+    printf("Usage: tinyscheme -?\n");
+    printf("or:    tinyscheme [<file1> <file2> ...]\n");
+    printf("followed by\n");
+    printf("          -1 <file> [<arg1> <arg2> ...]\n");
+    printf("          -c <Scheme commands> [<arg1> <arg2> ...]\n");
+    printf("assuming that the executable is named tinyscheme.\n");
+    printf("Use - as filename for stdin.\n");
+    return 1;
+  }
+  if(!scheme_init(&sc)) {
+    fprintf(stderr,"Could not initialize!\n");
+    return 2;
+  }
+  scheme_set_input_port_file(&sc, stdin);
+  scheme_set_output_port_file(&sc, stdout);
+#if USE_DL
+  scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
+#endif
+  argv++;
+  if(access(file_name,0)!=0) {
+    char *p=getenv("TINYSCHEMEINIT");
+    if(p!=0) {
+      file_name=p;
+    }
+  }
+  do {
+    if(strcmp(file_name,"-")==0) {
+      fin=stdin;
+    } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
+      pointer args=sc.NIL;
+      isfile=file_name[1]=='1';
+      file_name=*argv++;
+      if(strcmp(file_name,"-")==0) {
+        fin=stdin;
+      } else if(isfile) {
+        fin=fopen(file_name,"r");
+      }
+      for(;*argv;argv++) {
+        pointer value=mk_string(&sc,*argv);
+        args=cons(&sc,value,args);
+      }
+      args=reverse_in_place(&sc,sc.NIL,args);
+      scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
+
+    } else {
+      fin=fopen(file_name,"r");
+    }
+    if(isfile && fin==0) {
+      fprintf(stderr,"Could not open file %s\n",file_name);
+    } else {
+      if(isfile) {
+        scheme_load_named_file(&sc,fin,file_name);
+      } else {
+        scheme_load_string(&sc,file_name);
+      }
+      if(!isfile || fin!=stdin) {
+        if(sc.retcode!=0) {
+          fprintf(stderr,"Errors encountered reading %s\n",file_name);
+        }
+        if(isfile) {
+          fclose(fin);
+        }
+      }
+    }
+    file_name=*argv++;
+  } while(file_name!=0);
+  if(argc==1) {
+    scheme_load_named_file(&sc,stdin,0);
+  }
+  retcode=sc.retcode;
+  scheme_deinit(&sc);
+
+  return retcode;
+}
+
+#endif
+
+/*
+Local variables:
+c-file-style: "k&r"
+End:
+*/
diff --git a/tests/gpgscm/scheme.h b/tests/gpgscm/scheme.h
new file mode 100644 (file)
index 0000000..f4231c4
--- /dev/null
@@ -0,0 +1,266 @@
+/* SCHEME.H */
+
+#ifndef _SCHEME_H
+#define _SCHEME_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Default values for #define'd symbols
+ */
+#ifndef STANDALONE       /* If used as standalone interpreter */
+# define STANDALONE 1
+#endif
+
+#ifndef _MSC_VER
+# define USE_STRCASECMP 1
+# ifndef USE_STRLWR
+#   define USE_STRLWR 1
+# endif
+# define SCHEME_EXPORT
+#else
+# define USE_STRCASECMP 0
+# define USE_STRLWR 0
+# ifdef _SCHEME_SOURCE
+#  define SCHEME_EXPORT __declspec(dllexport)
+# else
+#  define SCHEME_EXPORT __declspec(dllimport)
+# endif
+#endif
+
+#if USE_NO_FEATURES
+# define USE_MATH 0
+# define USE_CHAR_CLASSIFIERS 0
+# define USE_ASCII_NAMES 0
+# define USE_STRING_PORTS 0
+# define USE_ERROR_HOOK 0
+# define USE_TRACING 0
+# define USE_COLON_HOOK 0
+# define USE_DL 0
+# define USE_PLIST 0
+#endif
+
+/*
+ * Leave it defined if you want continuations, and also for the Sharp Zaurus.
+ * Undefine it if you only care about faster speed and not strict Scheme compatibility.
+ */
+#define USE_SCHEME_STACK
+
+#if USE_DL
+# define USE_INTERFACE 1
+#endif
+
+
+#ifndef USE_MATH         /* If math support is needed */
+# define USE_MATH 1
+#endif
+
+#ifndef USE_CHAR_CLASSIFIERS  /* If char classifiers are needed */
+# define USE_CHAR_CLASSIFIERS 1
+#endif
+
+#ifndef USE_ASCII_NAMES  /* If extended escaped characters are needed */
+# define USE_ASCII_NAMES 1
+#endif
+
+#ifndef USE_STRING_PORTS      /* Enable string ports */
+# define USE_STRING_PORTS 1
+#endif
+
+#ifndef USE_TRACING
+# define USE_TRACING 1
+#endif
+
+#ifndef USE_PLIST
+# define USE_PLIST 0
+#endif
+
+/* To force system errors through user-defined error handling (see *error-hook*) */
+#ifndef USE_ERROR_HOOK
+# define USE_ERROR_HOOK 1
+#endif
+
+#ifndef USE_COLON_HOOK   /* Enable qualified qualifier */
+# define USE_COLON_HOOK 1
+#endif
+
+#ifndef USE_STRCASECMP   /* stricmp for Unix */
+# define USE_STRCASECMP 0
+#endif
+
+#ifndef USE_STRLWR
+# define USE_STRLWR 1
+#endif
+
+#ifndef STDIO_ADDS_CR    /* Define if DOS/Windows */
+# define STDIO_ADDS_CR 0
+#endif
+
+#ifndef INLINE
+# define INLINE
+#endif
+
+#ifndef USE_INTERFACE
+# define USE_INTERFACE 0
+#endif
+
+#ifndef SHOW_ERROR_LINE   /* Show error line in file */
+# define SHOW_ERROR_LINE 1
+#endif
+
+typedef struct scheme scheme;
+typedef struct cell *pointer;
+
+typedef void * (*func_alloc)(size_t);
+typedef void (*func_dealloc)(void *);
+
+/* table of functions required for foreign objects */
+typedef struct foreign_object_vtable {
+     void (*finalize)(scheme *sc, void *data);
+     void (*to_string)(scheme *sc, char *out, size_t size, void *data);
+} foreign_object_vtable;
+
+/* num, for generic arithmetic */
+typedef struct num {
+     char is_fixnum;
+     union {
+          long ivalue;
+          double rvalue;
+     } value;
+} num;
+
+SCHEME_EXPORT scheme *scheme_init_new(void);
+SCHEME_EXPORT scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free);
+SCHEME_EXPORT int scheme_init(scheme *sc);
+SCHEME_EXPORT int scheme_init_custom_alloc(scheme *sc, func_alloc, func_dealloc);
+SCHEME_EXPORT void scheme_deinit(scheme *sc);
+void scheme_set_input_port_file(scheme *sc, FILE *fin);
+void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end);
+SCHEME_EXPORT void scheme_set_output_port_file(scheme *sc, FILE *fin);
+void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end);
+SCHEME_EXPORT void scheme_load_file(scheme *sc, FILE *fin);
+SCHEME_EXPORT void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename);
+SCHEME_EXPORT void scheme_load_string(scheme *sc, const char *cmd);
+SCHEME_EXPORT pointer scheme_apply0(scheme *sc, const char *procname);
+SCHEME_EXPORT pointer scheme_call(scheme *sc, pointer func, pointer args);
+SCHEME_EXPORT pointer scheme_eval(scheme *sc, pointer obj);
+void scheme_set_external_data(scheme *sc, void *p);
+SCHEME_EXPORT void scheme_define(scheme *sc, pointer env, pointer symbol, pointer value);
+
+typedef pointer (*foreign_func)(scheme *, pointer);
+
+pointer _cons(scheme *sc, pointer a, pointer b, int immutable);
+pointer mk_integer(scheme *sc, long num);
+pointer mk_real(scheme *sc, double num);
+pointer mk_symbol(scheme *sc, const char *name);
+pointer gensym(scheme *sc);
+pointer mk_string(scheme *sc, const char *str);
+pointer mk_counted_string(scheme *sc, const char *str, int len);
+pointer mk_empty_string(scheme *sc, int len, char fill);
+pointer mk_character(scheme *sc, int c);
+pointer mk_foreign_func(scheme *sc, foreign_func f);
+pointer mk_foreign_object(scheme *sc, const foreign_object_vtable *vtable, void *data);
+void putstr(scheme *sc, const char *s);
+int list_length(scheme *sc, pointer a);
+int eqv(pointer a, pointer b);
+
+
+#if USE_INTERFACE
+struct scheme_interface {
+  void (*scheme_define)(scheme *sc, pointer env, pointer symbol, pointer value);
+  pointer (*cons)(scheme *sc, pointer a, pointer b);
+  pointer (*immutable_cons)(scheme *sc, pointer a, pointer b);
+  pointer (*reserve_cells)(scheme *sc, int n);
+  pointer (*mk_integer)(scheme *sc, long num);
+  pointer (*mk_real)(scheme *sc, double num);
+  pointer (*mk_symbol)(scheme *sc, const char *name);
+  pointer (*gensym)(scheme *sc);
+  pointer (*mk_string)(scheme *sc, const char *str);
+  pointer (*mk_counted_string)(scheme *sc, const char *str, int len);
+  pointer (*mk_character)(scheme *sc, int c);
+  pointer (*mk_vector)(scheme *sc, int len);
+  pointer (*mk_foreign_func)(scheme *sc, foreign_func f);
+  pointer (*mk_foreign_object)(scheme *sc, const foreign_object_vtable *vtable, void *data);
+  const foreign_object_vtable *(*get_foreign_object_vtable)(pointer p);
+  void *(*get_foreign_object_data)(pointer p);
+  void (*putstr)(scheme *sc, const char *s);
+  void (*putcharacter)(scheme *sc, int c);
+
+  int (*is_string)(pointer p);
+  char *(*string_value)(pointer p);
+  int (*is_number)(pointer p);
+  num (*nvalue)(pointer p);
+  long (*ivalue)(pointer p);
+  double (*rvalue)(pointer p);
+  int (*is_integer)(pointer p);
+  int (*is_real)(pointer p);
+  int (*is_character)(pointer p);
+  long (*charvalue)(pointer p);
+  int (*is_list)(scheme *sc, pointer p);
+  int (*is_vector)(pointer p);
+  int (*list_length)(scheme *sc, pointer vec);
+  long (*vector_length)(pointer vec);
+  void (*fill_vector)(pointer vec, pointer elem);
+  pointer (*vector_elem)(pointer vec, int ielem);
+  pointer (*set_vector_elem)(pointer vec, int ielem, pointer newel);
+  int (*is_port)(pointer p);
+
+  int (*is_pair)(pointer p);
+  pointer (*pair_car)(pointer p);
+  pointer (*pair_cdr)(pointer p);
+  pointer (*set_car)(pointer p, pointer q);
+  pointer (*set_cdr)(pointer p, pointer q);
+
+  int (*is_symbol)(pointer p);
+  char *(*symname)(pointer p);
+
+  int (*is_syntax)(pointer p);
+  int (*is_proc)(pointer p);
+  int (*is_foreign)(pointer p);
+  char *(*syntaxname)(pointer p);
+  int (*is_closure)(pointer p);
+  int (*is_macro)(pointer p);
+  pointer (*closure_code)(pointer p);
+  pointer (*closure_env)(pointer p);
+
+  int (*is_continuation)(pointer p);
+  int (*is_promise)(pointer p);
+  int (*is_environment)(pointer p);
+  int (*is_immutable)(pointer p);
+  void (*setimmutable)(pointer p);
+  void (*load_file)(scheme *sc, FILE *fin);
+  void (*load_string)(scheme *sc, const char *input);
+  pointer (*mk_port_from_file)(scheme *sc, FILE *f, int kind);
+};
+#endif
+
+#if !STANDALONE
+typedef struct scheme_registerable
+{
+  foreign_func  f;
+  const char *  name;
+}
+scheme_registerable;
+
+void scheme_register_foreign_func_list(scheme * sc,
+                                       scheme_registerable * list,
+                                       int n);
+
+#endif /* !STANDALONE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+/*
+Local variables:
+c-file-style: "k&r"
+End:
+*/
diff --git a/tests/gpgscm/t-child.c b/tests/gpgscm/t-child.c
new file mode 100644 (file)
index 0000000..fe2e7b4
--- /dev/null
@@ -0,0 +1,66 @@
+/* Sanity check for the process and IPC primitives.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+# include <fcntl.h>
+# include <io.h>
+#endif
+
+int
+main (int argc, char **argv)
+{
+#if _WIN32
+  if (! setmode (stdin, O_BINARY))
+    return 23;
+  if (! setmode (stdout, O_BINARY))
+    return 23;
+#endif
+
+  if (argc == 1)
+    return 2;
+  else if (strcmp (argv[1], "return0") == 0)
+    return 0;
+  else if (strcmp (argv[1], "return1") == 0)
+    return 1;
+  else if (strcmp (argv[1], "return77") == 0)
+    return 77;
+  else if (strcmp (argv[1], "hello_stdout") == 0)
+    fprintf (stdout, "hello");
+  else if (strcmp (argv[1], "hello_stderr") == 0)
+    fprintf (stderr, "hello");
+  else if (strcmp (argv[1], "cat") == 0)
+    while (! feof (stdin))
+      {
+        char buffer[4096];
+        size_t bytes_read;
+        bytes_read = fread (buffer, 1, sizeof buffer, stdin);
+        fwrite (buffer, 1, bytes_read, stdout);
+      }
+  else
+    {
+      fprintf (stderr, "unknown command %s\n", argv[1]);
+      return 2;
+    }
+  return 0;
+}
diff --git a/tests/gpgscm/t-child.scm b/tests/gpgscm/t-child.scm
new file mode 100644 (file)
index 0000000..27928f6
--- /dev/null
@@ -0,0 +1,93 @@
+;; Tests for the low-level process and IPC primitives.
+;;
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(echo "Testing process and IPC primitives...")
+
+(define (qualify executable)
+  (string-append executable (getenv "EXEEXT")))
+
+(assert (= 0 (call `(,(qualify "t-child") "return0"))))
+(assert (= 1 (call `(,(qualify "t-child") "return1"))))
+(assert (= 77 (call `(,(qualify "t-child") "return77"))))
+
+(let ((r (call-with-io `(,(qualify "t-child") "return0") "")))
+  (assert (= 0 (:retcode r)))
+  (assert (string=? "" (:stdout r)))
+  (assert (string=? "" (:stderr r))))
+
+(let ((r (call-with-io `(,(qualify "t-child") "return1") "")))
+  (assert (= 1 (:retcode r)))
+  (assert (string=? "" (:stdout r)))
+  (assert (string=? "" (:stderr r))))
+
+(let ((r (call-with-io `(,(qualify "t-child") "return77") "")))
+  (assert (= 77 (:retcode r)))
+  (assert (string=? "" (:stdout r)))
+  (assert (string=? "" (:stderr r))))
+
+(let ((r (call-with-io `(,(qualify "t-child") "hello_stdout") "")))
+  (assert (= 0 (:retcode r)))
+  (assert (string=? "hello" (:stdout r)))
+  (assert (string=? "" (:stderr r))))
+
+(let ((r (call-with-io `(,(qualify "t-child") "hello_stderr") "")))
+  (assert (= 0 (:retcode r)))
+  (assert (string=? "" (:stdout r)))
+  (assert (string=? "hello" (:stderr r))))
+
+(let ((r (call-with-io `(,(qualify "t-child") "cat") "hellohello")))
+  (assert (= 0 (:retcode r)))
+  (assert (string=? "hellohello" (:stdout r)))
+  (assert (string=? "" (:stderr r))))
+
+(define (spawn what)
+  (spawn-process-fd what CLOSED_FD STDOUT_FILENO STDERR_FILENO))
+
+(let ((pid0 (spawn `(,(qualify "t-child") "return0")))
+      (pid1 (spawn `(,(qualify "t-child") "return0"))))
+  (assert (equal? '(0 0)
+                 (wait-processes '("child0" "child1") (list pid0 pid1) #t))))
+
+(let ((pid0 (spawn `(,(qualify "t-child") "return1")))
+      (pid1 (spawn `(,(qualify "t-child") "return0"))))
+  (assert (equal? '(1 0)
+                 (wait-processes '("child0" "child1") (list pid0 pid1) #t))))
+
+(let ((pid0 (spawn `(,(qualify "t-child") "return0")))
+      (pid1 (spawn `(,(qualify "t-child") "return77")))
+      (pid2 (spawn `(,(qualify "t-child") "return1"))))
+  (assert (equal? '(0 77 1)
+                 (wait-processes '("child0" "child1" "child2")
+                                 (list pid0 pid1 pid2) #t))))
+
+(let* ((p (pipe))
+       (pid0 (spawn-process-fd
+              `(,(qualify "t-child") "hello_stdout")
+              CLOSED_FD (:write-end p) STDERR_FILENO))
+       (_ (close (:write-end p)))
+       (pid1 (spawn-process-fd
+              `(,(qualify "t-child") "cat")
+              (:read-end p) STDOUT_FILENO STDERR_FILENO)))
+  (close (:read-end p))
+  (assert
+   (equal? '(0 0)
+          (wait-processes '("child0" "child1") (list pid0 pid1) #t))))
+(echo " world.")
+
+(echo "All good.")
diff --git a/tests/gpgscm/tests.scm b/tests/gpgscm/tests.scm
new file mode 100644 (file)
index 0000000..c32e2fa
--- /dev/null
@@ -0,0 +1,443 @@
+;; Common definitions for writing tests.
+;;
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+;; Trace displays and returns the given value.  A debugging aid.
+(define (trace x)
+  (display x)
+  (newline)
+  x)
+
+;; Stringification.
+(define (stringify expression)
+  (let ((p (open-output-string)))
+    (write expression p)
+    (get-output-string p)))
+
+;; Reporting.
+(define (echo . msg)
+  (for-each (lambda (x) (display x) (display " ")) msg)
+  (newline))
+
+(define (info . msg)
+  (apply echo msg)
+  (flush-stdio))
+
+(define (error . msg)
+  (apply info msg)
+  (exit 1))
+
+(define (skip . msg)
+  (apply info msg)
+  (exit 77))
+
+(define (make-counter)
+  (let ((c 0))
+    (lambda ()
+      (let ((r c))
+       (set! c (+ 1 c))
+       r))))
+
+(define *progress-nesting* 0)
+
+(define (call-with-progress msg what)
+  (set! *progress-nesting* (+ 1 *progress-nesting*))
+  (if (= 1 *progress-nesting*)
+      (begin
+       (info msg)
+       (display "    > ")
+       (flush-stdio)
+       (what (lambda (item)
+             (display item)
+             (display " ")
+             (flush-stdio)))
+       (info "< "))
+      (begin
+       (what (lambda (item) (display ".") (flush-stdio)))
+       (display " ")
+       (flush-stdio)))
+  (set! *progress-nesting* (- *progress-nesting* 1)))
+
+(define (for-each-p msg proc lst)
+  (for-each-p' msg proc (lambda (x) x) lst))
+
+(define (for-each-p' msg proc fmt lst)
+  (call-with-progress
+   msg
+   (lambda (progress)
+     (for-each (lambda (a)
+                (progress (fmt a))
+                (proc a))
+              lst))))
+
+;; Process management.
+(define CLOSED_FD -1)
+(define (call-with-fds what infd outfd errfd)
+  (wait-process (stringify what) (spawn-process-fd what infd outfd errfd) #t))
+(define (call what)
+  (call-with-fds what
+                CLOSED_FD
+                (if (< *verbose* 0) STDOUT_FILENO CLOSED_FD)
+                (if (< *verbose* 0) STDERR_FILENO CLOSED_FD)))
+
+;; Accessor functions for the results of 'spawn-process'.
+(define :stdin car)
+(define :stdout cadr)
+(define :stderr caddr)
+(define :pid cadddr)
+
+(define (call-with-io what in)
+  (let ((h (spawn-process what 0)))
+    (es-write (:stdin h) in)
+    (es-fclose (:stdin h))
+    (let* ((out (es-read-all (:stdout h)))
+          (err (es-read-all (:stderr h)))
+          (result (wait-process (car what) (:pid h) #t)))
+      (es-fclose (:stdout h))
+      (es-fclose (:stderr h))
+      (list result out err))))
+
+;; Accessor function for the results of 'call-with-io'.  ':stdout' and
+;; ':stderr' can also be used.
+(define :retcode car)
+
+(define (call-check what)
+  (let ((result (call-with-io what "")))
+    (if (= 0 (:retcode result))
+       (:stdout result)
+       (throw (list what "failed:" (:stderr result))))))
+
+(define (call-popen command input-string)
+  (let ((result (call-with-io command input-string)))
+    (if (= 0 (:retcode result))
+       (:stdout result)
+       (throw (:stderr result)))))
+
+;;
+;; estream helpers.
+;;
+
+(define (es-read-all stream)
+  (let loop
+      ((acc ""))
+    (if (es-feof stream)
+       acc
+       (loop (string-append acc (es-read stream 4096))))))
+
+;;
+;; File management.
+;;
+(define (file-exists? name)
+  (call-with-input-file name (lambda (port) #t)))
+
+(define (file=? a b)
+  (file-equal a b #t))
+
+(define (text-file=? a b)
+  (file-equal a b #f))
+
+(define (file-copy from to)
+  (catch '() (unlink to))
+  (letfd ((source (open from (logior O_RDONLY O_BINARY)))
+         (sink (open to (logior O_WRONLY O_CREAT O_BINARY) #o600)))
+    (splice source sink)))
+
+(define (text-file-copy from to)
+  (catch '() (unlink to))
+  (letfd ((source (open from O_RDONLY))
+         (sink (open to (logior O_WRONLY O_CREAT) #o600)))
+    (splice source sink)))
+
+(define (path-join . components)
+  (let loop ((acc #f) (rest (filter (lambda (s)
+                                     (not (string=? "" s))) components)))
+    (if (null? rest)
+       acc
+       (loop (if (string? acc)
+                 (string-append acc "/" (car rest))
+                 (car rest))
+             (cdr rest)))))
+(assert (string=? (path-join "foo" "bar" "baz") "foo/bar/baz"))
+(assert (string=? (path-join "" "bar" "baz") "bar/baz"))
+
+(define (canonical-path path)
+  (if (char=? #\/ (string-ref path 0))
+      path
+      (string-append (getcwd) "/" path)))
+
+(define (in-srcdir what)
+  (canonical-path (string-append (getenv "srcdir") "/" what)))
+
+(define (with-path name)
+  (let loop ((path (string-split (getenv "GPGSCM_PATH") #\:)))
+    (if (null? path)
+       name
+       (let* ((qualified-name (string-append (car path) "/" name))
+              (file-exists (call-with-input-file qualified-name
+                             (lambda (x) #t))))
+         (if file-exists
+             qualified-name
+             (loop (cdr path)))))))
+
+(define (basename path)
+  (let ((i (string-index path #\/)))
+    (if (equal? i #f)
+       path
+       (basename (substring path (+ 1 i) (string-length path))))))
+
+(define (basename-suffix path suffix)
+  (basename
+   (if (string-suffix? path suffix)
+       (substring path 0 (- (string-length path) (string-length suffix)))
+       path)))
+
+;; Helper for (pipe).
+(define :read-end car)
+(define :write-end cadr)
+
+;; let-like macro that manages file descriptors.
+;;
+;; (letfd <bindings> <body>)
+;;
+;; Bind all variables given in <bindings> and initialize each of them
+;; to the given initial value, and close them after evaluting <body>.
+(macro (letfd form)
+  (let ((result-sym (gensym)))
+    `((lambda (,(caaadr form))
+       (let ((,result-sym
+              ,(if (= 1 (length (cadr form)))
+                   `(begin ,@(cddr form))
+                   `(letfd ,(cdadr form) ,@(cddr form)))))
+         (close ,(caaadr form))
+         ,result-sym)) ,@(cdaadr form))))
+
+(macro (with-working-directory form)
+  (let ((result-sym (gensym)) (cwd-sym (gensym)))
+    `(let* ((,cwd-sym (getcwd))
+           (_ (if ,(cadr form) (chdir ,(cadr form))))
+           (,result-sym (begin ,@(cddr form))))
+       (chdir ,cwd-sym)
+       ,result-sym)))
+
+(macro (with-temporary-working-directory form)
+  (let ((result-sym (gensym)) (cwd-sym (gensym)) (tmp-sym (gensym)))
+    `(let* ((,cwd-sym (getcwd))
+           (,tmp-sym (mkdtemp (path-join (getenv "TMP") "gpgscm-XXXXXX")))
+           (_ (chdir ,tmp-sym))
+           (,result-sym (begin ,@(cdr form))))
+       (chdir ,cwd-sym)
+       (unlink-recursively ,tmp-sym)
+       ,result-sym)))
+
+(define (make-temporary-file . args)
+  (canonical-path (path-join
+                  (mkdtemp (path-join (getenv "TMP") "gpgscm-XXXXXX"))
+                  (if (null? args) "a" (car args)))))
+
+(define (remove-temporary-file filename)
+  (catch '()
+    (unlink filename))
+  (let ((dirname (substring filename 0 (string-rindex filename #\/))))
+    (catch (echo "removing temporary directory" dirname "failed")
+      (rmdir dirname))))
+
+;; let-like macro that manages temporary files.
+;;
+;; (lettmp <bindings> <body>)
+;;
+;; Bind all variables given in <bindings>, initialize each of them to
+;; a string representing an unique path in the filesystem, and delete
+;; them after evaluting <body>.
+(macro (lettmp form)
+  (let ((result-sym (gensym)))
+    `((lambda (,(caadr form))
+       (let ((,result-sym
+              ,(if (= 1 (length (cadr form)))
+                   `(begin ,@(cddr form))
+                   `(lettmp ,(cdadr form) ,@(cddr form)))))
+         (remove-temporary-file ,(caadr form))
+         ,result-sym)) (make-temporary-file ,(symbol->string (caadr form))))))
+
+(define (check-execution source transformer)
+  (lettmp (sink)
+         (transformer source sink)))
+
+(define (check-identity source transformer)
+  (lettmp (sink)
+         (transformer source sink)
+         (if (not (file=? source sink))
+             (error "mismatch"))))
+
+;;
+;; Monadic pipe support.
+;;
+
+(define pipeM
+  (package
+   (define (new procs source sink producer)
+     (package
+      (define (dump)
+       (write (list procs source sink producer))
+       (newline))
+      (define (add-proc command pid)
+       (new (cons (list command pid) procs) source sink producer))
+      (define (commands)
+       (map car procs))
+      (define (pids)
+       (map cadr procs))
+      (define (set-source source')
+       (new procs source' sink producer))
+      (define (set-sink sink')
+       (new procs source sink' producer))
+      (define (set-producer producer')
+       (if producer
+           (throw "producer already set"))
+       (new procs source sink producer'))))))
+
+
+(define (pipe:do . commands)
+  (let loop ((M (pipeM::new '() CLOSED_FD CLOSED_FD #f)) (cmds commands))
+    (if (null? cmds)
+       (begin
+         (if M::producer (M::producer))
+         (if (not (null? M::procs))
+             (let* ((retcodes (wait-processes (map stringify (M::commands))
+                                              (M::pids) #t))
+                    (results (map (lambda (p r) (append p (list r)))
+                                  M::procs retcodes))
+                    (failed (filter (lambda (x) (not (= 0 (caddr x))))
+                                    results)))
+               (if (not (null? failed))
+                   (throw failed))))) ; xxx nicer reporting
+       (if (and (= 2 (length cmds)) (number? (cadr cmds)))
+           ;; hack: if it's an fd, use it as sink
+           (let ((M' ((car cmds) (M::set-sink (cadr cmds)))))
+             (if (> M::source 2) (close M::source))
+             (if (> (cadr cmds) 2) (close (cadr cmds)))
+             (loop M' '()))
+           (let ((M' ((car cmds) M)))
+             (if (> M::source 2) (close M::source))
+             (loop M' (cdr cmds)))))))
+
+(define (pipe:open pathname flags)
+  (lambda (M)
+    (M::set-source (open pathname flags))))
+
+(define (pipe:defer producer)
+  (lambda (M)
+    (let* ((p (outbound-pipe))
+          (M' (M::set-source (:read-end p))))
+      (M'::set-producer (lambda ()
+                         (producer (:write-end p))
+                         (close (:write-end p)))))))
+(define (pipe:echo data)
+ (pipe:defer (lambda (sink) (display data (fdopen sink "wb")))))
+
+(define (pipe:spawn command)
+  (lambda (M)
+    (define (do-spawn M new-source)
+      (let ((pid (spawn-process-fd command M::source M::sink
+                                  (if (> *verbose* 0)
+                                      STDERR_FILENO CLOSED_FD)))
+           (M' (M::set-source new-source)))
+       (M'::add-proc command pid)))
+    (if (= CLOSED_FD M::sink)
+       (let* ((p (pipe))
+              (M' (do-spawn (M::set-sink (:write-end p)) (:read-end p))))
+         (close (:write-end p))
+         (M'::set-sink CLOSED_FD))
+       (do-spawn M CLOSED_FD))))
+
+(define (pipe:splice sink)
+  (lambda (M)
+    (splice M::source sink)
+    (M::set-source CLOSED_FD)))
+
+(define (pipe:write-to pathname flags mode)
+  (open pathname flags mode))
+
+;;
+;; Monadic transformer support.
+;;
+
+(define (tr:do . commands)
+  (let loop ((tmpfiles '()) (source  #f) (cmds commands))
+    (if (null? cmds)
+       (for-each remove-temporary-file tmpfiles)
+       (let* ((v ((car cmds) tmpfiles source))
+              (tmpfiles' (car v))
+              (sink (cadr v))
+              (error (caddr v)))
+         (if error
+             (begin
+               (for-each remove-temporary-file tmpfiles')
+               (throw error)))
+         (loop tmpfiles' sink (cdr cmds))))))
+
+(define (tr:open pathname)
+  (lambda (tmpfiles source)
+    (list tmpfiles pathname #f)))
+
+(define (tr:spawn input command)
+  (lambda (tmpfiles source)
+    (if (and (member '**in** command) (not source))
+       (error (string-append (stringify cmd) " needs an input")))
+    (let* ((t (make-temporary-file))
+          (cmd (map (lambda (x)
+                      (cond
+                       ((equal? '**in** x) source)
+                       ((equal? '**out** x) t)
+                       (else x))) command)))
+      (catch (list (cons t tmpfiles) t *error*)
+            (call-popen cmd input)
+            (if (and (member '**out** command) (not (file-exists? t)))
+                (error (string-append (stringify cmd)
+                                      " did not produce '" t "'.")))
+            (list (cons t tmpfiles) t #f)))))
+
+(define (tr:write-to pathname)
+  (lambda (tmpfiles source)
+    (rename source pathname)
+    (list tmpfiles pathname #f)))
+
+(define (tr:pipe-do . commands)
+  (lambda (tmpfiles source)
+    (let ((t (make-temporary-file)))
+      (apply pipe:do
+        `(,@(if source `(,(pipe:open source (logior O_RDONLY O_BINARY))) '())
+         ,@commands
+         ,(pipe:write-to t (logior O_WRONLY O_BINARY O_CREAT) #o600)))
+      (list (cons t tmpfiles) t #f))))
+
+(define (tr:assert-identity reference)
+  (lambda (tmpfiles source)
+    (if (not (file=? source reference))
+       (error "mismatch"))
+    (list tmpfiles source #f)))
+
+(define (tr:assert-weak-identity reference)
+  (lambda (tmpfiles source)
+    (if (not (text-file=? source reference))
+       (error "mismatch"))
+    (list tmpfiles source #f)))
+
+(define (tr:call-with-content function . args)
+  (lambda (tmpfiles source)
+    (catch (list tmpfiles source *error*)
+          (apply function `(,(call-with-input-file source read-all) ,@args)))
+    (list tmpfiles source #f)))
index 0f581c2..9c82d66 100644 (file)
@@ -26,21 +26,20 @@ include $(top_srcdir)/am/cmacros.am
 
 AM_CFLAGS =
 
-TESTS_ENVIRONMENT = GPG_AGENT_INFO= LC_ALL=C
+TMP ?= /tmp
 
-TESTS = from-classic.test \
-       extended-private-key-format.test
+TESTS_ENVIRONMENT = GPG_AGENT_INFO= LC_ALL=C \
+       PATH=../gpgscm:$(PATH) \
+       TMP=$(TMP) \
+       GPGSCM_PATH=$(top_srcdir)/tests/gpgscm:$(top_srcdir)/tests/migrations
 
-TEST_FILES = from-classic.gpghome/pubring.gpg.asc \
-            from-classic.gpghome/secring.gpg.asc \
-            from-classic.gpghome/trustdb.gpg.asc \
-            extended-private-key-format.gpghome/trustdb.gpg.asc \
-            extended-private-key-format.gpghome/pubring.kbx.asc \
-            extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc \
-            extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc \
-            extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc
+TESTS = from-classic.scm \
+       extended-pkf.scm
 
-EXTRA_DIST = $(TESTS) $(TEST_FILES)
+TEST_FILES = from-classic.tar.asc \
+            extended-pkf.tar.asc
+
+EXTRA_DIST = common.scm $(TESTS) $(TEST_FILES)
 
 CLEANFILES = prepared.stamp x y yy z out err  $(data_files) \
             plain-1 plain-2 plain-3 trustdb.gpg *.lock .\#lk* \
diff --git a/tests/migrations/common.scm b/tests/migrations/common.scm
new file mode 100644 (file)
index 0000000..79f69e5
--- /dev/null
@@ -0,0 +1,39 @@
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(if (string=? "" (getenv "srcdir"))
+    (error "not called from make"))
+
+(setenv "GNUPGHOME" "" #t)
+
+(define (qualify executable)
+  (string-append executable (getenv "EXEEXT")))
+
+;; We may not use a relative name for gpg-agent.
+(define GPG-AGENT (qualify (string-append (getcwd) "/../../agent/gpg-agent")))
+(define GPG `(,(qualify (string-append (getcwd) "/../../g10/gpg"))
+             --no-permission-warning --no-greeting
+             --no-secmem-warning --batch
+             ,(string-append "--agent-program=" GPG-AGENT
+                             "|--debug-quick-random")))
+(define GPGTAR (qualify (string-append (getcwd) "/../../tools/gpgtar")))
+
+(define (untar-armored source-name)
+  (pipe:do
+   (pipe:open source-name (logior O_RDONLY O_BINARY))
+   (pipe:spawn `(,@GPG --dearmor))
+   (pipe:spawn `(,GPGTAR --extract --directory=. -))))
diff --git a/tests/migrations/extended-pkf.scm b/tests/migrations/extended-pkf.scm
new file mode 100755 (executable)
index 0000000..3e76532
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "common.scm"))
+
+(define src-tarball (in-srcdir "extended-pkf.tar.asc"))
+
+(define (setup)
+  (untar-armored src-tarball)
+  (setenv "GNUPGHOME" (getcwd) #t))
+
+(define (trigger-migration)
+  (call-check `(,@GPG --list-secret-keys)))
+
+(define (assert-keys-usable)
+  (for-each
+   (lambda (keyid)
+     (catch (error "Key not found:" keyid)
+           (call-check `(,@GPG --list-secret-keys ,keyid))))
+   '("C40FDECF" "ECABF51D")))
+
+(info "Testing the extended private key format ...")
+(with-temporary-working-directory
+ (setup)
+ (assert-keys-usable))
+
+;; XXX try changing a key, and check that the format is not changed.
diff --git a/tests/migrations/extended-pkf.tar.asc b/tests/migrations/extended-pkf.tar.asc
new file mode 100644 (file)
index 0000000..adbe174
--- /dev/null
@@ -0,0 +1,220 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+cHJpdmF0ZS1rZXlzLXYxLmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAADAwMDA3NTUAMDAwMTc1MAAwMDAxNzUwADAwMDAwMDAwMDAwADEyNzM2NzI1
+MzA2ADAxNDU0NwAgNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHRleXRob29uAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAdGV5dGhvb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwcml2YXRlLWtleXMtdjEu
+ZC84QjVBQkYzRUY5RUI4RDk2QjkxQTBCOEMyQzQ0MDFDOTFDODM0QzM0LmtleQAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDY0NAAwMDAx
+NzUwADAwMDE3NTAAMDAwMDAwMDEyMDQAMTI3MzY3MjUyNTYAMDIyMTAyACAwAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AHVzdGFyADAwdGV5dGhvb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ZXl0aG9v
+bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAEtleTogKHByaXZhdGUta2V5IChlbGcgKHAgIzAwQ0NE
+OEIxRjlEQUM3NEQ4MDhDQzUyRjBEODk0NjREQTU1NEM2OUQ2N0YzCiAzMjNDNDJB
+OTVDOTk2MkRGNDIxMjZFQzBFMDk3MUY0OUI4MTE1MjlBNkEyQUU5RjBBREVCODM5
+QTYzNDYxNUNENTZGQTU0CiBGNUEwQjdFRjI1QTBFMkZFODQzRkEyRTZFMDIxQ0FC
+NDExOUU2MDM5NEM5RDZBM0Y3QUQ0RjU3Nzk2RDM2NjY5QTUxMjY2CiBDMjdBOEQx
+QzVBNkI0MTQxRDVDODMxRTg0NTQxRjNDODExRTg5MDc4OTgwMzM4Mjk1RjgyQjdG
+N0ZENDMzM0VGRDkzMzEyCiBGMkFCIykoZyAjMDYjKSh5ICMzNzczQTZEOUVDODg5
+RDc2RTMyNEQ2RTVFQzIxQkQ0NTY5OTgzMUFFNEZEMEFFMDM3ODIwCiA1QkFFNUI4
+Q0U4NUZBREFCRDdFNkI3QzczMDI1Q0IzRDczMEQ1QzU4MjkwMzRENzZCRTA4NTVD
+MkU5RkY3QTQ5MjNFRkZBCiBGMTZBOTY2Njk0NERCQzYyOTQ4MzhGQzNGMDlGRjk2
+NEE4RDAyM0NCOEVCQTMzMkZCMDUxRUEwMjgyMEVFNjEyMEZGQkU2CiAyQjM2QTIw
+MkIzQzc1MkY5REE3NkIyRUMxMUE2N0QyRTM1RTY2RUMxMDYzNTg3QjIyNTAwRThB
+NDZEMTU3Qjc1IykoeCAjCiA2OTE1QzZDRUQyNTgxNDNGODkzN0IxMzM1RjQ4ODdG
+MDA0MkI3QzYzMDA1Mzk4RjkzOTZCQjg1MzIzOENCNiMpKSkKNjE1Q0Q1NkZBNTQK
+IEY1QTBCN0VGMjVBMEUyRkU4NDNGQTJFNkUwMjFDQUI0MTE5RTYwMzk0QzlENkEz
+RjdBRDRGNTc3OTZEMzY2NjlBNTEyNjYKIEMyN0E4RDFDNUE2QjQxNDFENUM4MzFF
+ODQ1NDFGM0M4MTFFODkwNzg5ODAzMzgyOTVGODJCN0Y3RkQ0MzMzRUZEOTMzMTIK
+IEYyQUIjKShnICMwNiMpKHkgIzM3NzNBNkQ5RUM4ODlENzZFMzI0RDZFNUVDMjFC
+RDQ1Njk5ODMxQUU0RkQwQUUwMzc4MjAKIDVCQUU1QjhDRTg1RkFEQUJEN0U2QjdD
+NzMwMjVDQjNENzMwRDVDNTgyOTAzNEQ3NkJFMDg1NUMyRTlGRjdBNDkyM0VGRkEK
+IEYxNkE5NjY2OTQ0REJDNjI5NDgzOEZDM0YwOUZGOTY0QThEMDIzQ0I4RUJBMzMy
+RkIwNTFFQTAyODIwRUU2MTIwRkZCRTYKIDJCMzZBMjBwcml2YXRlLWtleXMtdjEu
+ZC8zNDNEOEFGNzk3OTZFRTEwN0Q2NDVBMjc4N0E5RDkyNTJGOTI0RTZGLmtleQAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDY0NAAwMDAx
+NzUwADAwMDE3NTAAMDAwMDAwMDA3NTQAMTI3MzY3MjUyNTYAMDIyMDQwACAwAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AHVzdGFyADAwdGV5dGhvb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ZXl0aG9v
+bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAACgxMTpwcml2YXRlLWtleSgzOmRzYSgxOnAxMjk6AKxx
+qlg9Kz9DZ/3N52BC0w+JtYKke39vpdWVDHR3MHmMJ/31Y2iSpm0fvRs3h1j9/fBV
+mLOZglNQyH62SxdJyZwCelkZzfUy/qLm9Qaqi7wpg0p4EbmWdoFF/A1Zg/MU7D5w
+5xu+EA1J77Z6QyALN9rIOXZ7rLLa64lw/MV4LdIPKSgxOnEyMToAuOPYbSW26ea5
+CR7wQ7OGMRCJJOcpKDE6ZzEyODpfiE8aUjDk+UeuwbuF1qGFO51XmFEaW+iyfCyt
+gle8oBAsBXURXbpIhhQfmkz/Jxesbbl2pWgbnq5CqeEF1SqjiJKezFjdkwDjoPXh
+ERz0//8Ia8n+PZnjWDDy7ygHutLnR2O+hpZvmbKPtuFpxMF19qHdTx1VdwiLVkW+
+2JoYBikoMTp5MTI4OgIF7eNIdpaYiB0427un4ggc26+Y9nkF93DaMnZEaYSeum6g
+/g7D1vwINFgQkMYEWi4DK3W+uH0E/n8o20wS2wvMrbeYaQm5v6ucd001wwFDY6Ad
+wpwP7UCLQcu6qqvwNHdxWYK6+gIsSufLmeMGrsvC0WQqYeu1GfGpHIMCZJlZKSgx
+OngyMDp/2Na42QEhjCvSBm9cv2Qyk9M5EykpKQAAAAAAAAAAAAAAAAAAAAAAAAAA
+cHJpdmF0ZS1rZXlzLXYxLmQvMTNGREI4ODA5QjE3QzU1NDc3NzlGOUQyMDVDNDVG
+NDdDRTAyMTdDRS5rZXkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAADAwMDA2NDQAMDAwMTc1MAAwMDAxNzUwADAwMDAwMDAxNzQyADEyNzM2NzI1
+MjU2ADAyMjAzMgAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHRleXRob29uAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAdGV5dGhvb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLZXk6IChwcml2YXRlLWtl
+eSAocnNhIChuICMwMEE4NTI1Njc2RUNFNEQ3NUZFNkQwMDczRjJCRjk5QTZGNDkz
+M0NFQkRENAogNTI4QUY1NkU0QzYxRTJGNzMxMjQ3MzkzNjQ1RERBRjU4RUFERDU2
+NTI5QzI1Mzk3NzgyMzY0NjNERjJENDU4NTIwRTgwRQogMzRDMDU4MjQyQjNGRjg4
+REQzOUE4ODNCNDc1QjY2Q0VBQUJCQzk5ODlGRjAxRkZFNzM3NjYwRTlCNjFCQjlE
+QzkxMjA1RAogNDI4RkZGRThGNjc1RkFFRjYxMzY1OEM3MkRBNkQ3NTBDMEVCQzQw
+QUY2MjNEMjA2NjkyQzgyNTE0QzQwNEQ4ODI1QUI3MAogMTAwMSMpKGUgIzAxMDEj
+KShkICMwMEJDQTAwMTQ0ODVGQjc2RDUwRTlCNkNCQTU3MjFBQzExMjEzOTBGODYw
+OEQ0MDg0QgogRDA0NUE4NzZERjM4MTBGMTE0QkMyRDY4RUI1NTJFNjFCMDFFREJD
+MjQ4MUYwOEM4MjgzMkUwMEUyNzlENjdBODUzMDU1RAogQ0FFNUMyMzU2ODUxQ0JF
+MzZENjEwQzREMkFCNDNGQTY1NTk4NUM0NDY5RDFEOTExRTFBRkQ4MTdFQUE1RkVF
+MEZGMjY1NwogNEMzNTlFMTc1Mjg3MDUyMTk0NTNCNTFBRUMxMERCRjc1NjJCMDYx
+RDVDNjZDMzVCQjNGOUYwQjIyMkI5RDE5NkI5IykocAogICMwMEMzM0M1ODA2Mzk5
+NkJENTk3NTJBQUJERkRBQ0RBQTdCNEI2NkFBMTc1NEVFMEQ4OUI3Nzk0RjBERThG
+RjcyNEM1NAogOUZGMTEyQTMzMjkyQkI5RDdCQ0VFNzk0RjA4MDI0QzNFNTVGRDgy
+MzNGNTA3OUVENDk5MUM0REYyNjE4RDkjKShxICMwMAogRENCNTk0NUYwMEYxQUY0
+MzhCRDRDMzExQjhCQUNBM0Q5REIwQUQxNjUxOTg2NTM0MjAzMEYxREYzMDU3RTU1
+MzJDNDdGNQogOEQzMzAzQ0JBM0M4QTI5ODE0RjYxN0I3QjNERUU5OEZBQUFBRUU4
+MTFCNDk4RkFBRjIxNzdCNzc2OSMpKHUgIzI5RkIyRAogRjY5QjIzNUE0OUE5MDZC
+MTBFRjdEOEY4MUFBRUE4QUQ4MUU3Q0RERTFGNEE3OUNFMjQ0QkY4RkNFNkRENUVC
+MTgxMUIwQgogRDVFNTE2NUI5NTcwODUwMzY5MDFERDI4NUE2MjhDMjk3QTc4MkRB
+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
+MDAwMjI2MAAxMjczNjcyNTI1NgAwMTM2MjcAIDAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDB0ZXl0aG9v
+bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHRleXRob29uAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AWdwZwMDAQUBAgAAVxi2IwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAA==
+=Joz2
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc b/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc
deleted file mode 100644 (file)
index d9192b1..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-S2V5OiAocHJpdmF0ZS1rZXkgKHJzYSAobiAjMDBBODUyNTY3NkVDRTRENzVGRTZE
-MDA3M0YyQkY5OUE2RjQ5MzNDRUJERDQKIDUyOEFGNTZFNEM2MUUyRjczMTI0NzM5
-MzY0NUREQUY1OEVBREQ1NjUyOUMyNTM5Nzc4MjM2NDYzREYyRDQ1ODUyMEU4MEUK
-IDM0QzA1ODI0MkIzRkY4OEREMzlBODgzQjQ3NUI2NkNFQUFCQkM5OTg5RkYwMUZG
-RTczNzY2MEU5QjYxQkI5REM5MTIwNUQKIDQyOEZGRkU4RjY3NUZBRUY2MTM2NThD
-NzJEQTZENzUwQzBFQkM0MEFGNjIzRDIwNjY5MkM4MjUxNEM0MDREODgyNUFCNzAK
-IDEwMDEjKShlICMwMTAxIykoZCAjMDBCQ0EwMDE0NDg1RkI3NkQ1MEU5QjZDQkE1
-NzIxQUMxMTIxMzkwRjg2MDhENDA4NEIKIEQwNDVBODc2REYzODEwRjExNEJDMkQ2
-OEVCNTUyRTYxQjAxRURCQzI0ODFGMDhDODI4MzJFMDBFMjc5RDY3QTg1MzA1NUQK
-IENBRTVDMjM1Njg1MUNCRTM2RDYxMEM0RDJBQjQzRkE2NTU5ODVDNDQ2OUQxRDkx
-MUUxQUZEODE3RUFBNUZFRTBGRjI2NTcKIDRDMzU5RTE3NTI4NzA1MjE5NDUzQjUx
-QUVDMTBEQkY3NTYyQjA2MUQ1QzY2QzM1QkIzRjlGMEIyMjJCOUQxOTZCOSMpKHAK
-ICAjMDBDMzNDNTgwNjM5OTZCRDU5NzUyQUFCREZEQUNEQUE3QjRCNjZBQTE3NTRF
-RTBEODlCNzc5NEYwREU4RkY3MjRDNTQKIDlGRjExMkEzMzI5MkJCOUQ3QkNFRTc5
-NEYwODAyNEMzRTU1RkQ4MjMzRjUwNzlFRDQ5OTFDNERGMjYxOEQ5IykocSAjMDAK
-IERDQjU5NDVGMDBGMUFGNDM4QkQ0QzMxMUI4QkFDQTNEOURCMEFEMTY1MTk4NjUz
-NDIwMzBGMURGMzA1N0U1NTMyQzQ3RjUKIDhEMzMwM0NCQTNDOEEyOTgxNEY2MTdC
-N0IzREVFOThGQUFBQUVFODExQjQ5OEZBQUYyMTc3Qjc3NjkjKSh1ICMyOUZCMkQK
-IEY2OUIyMzVBNDlBOTA2QjEwRUY3RDhGODFBQUVBOEFEODFFN0NEREUxRjRBNzlD
-RTI0NEJGOEZDRTZERDVFQjE4MTFCMEIKIEQ1RTUxNjVCOTU3MDg1MDM2OTAxREQy
-ODVBNjI4QzI5N0E3ODJEQTgxNTczQTQzRDFDMDkjKSkpCg==
-=laTh
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc b/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc
deleted file mode 100644 (file)
index 1eede1c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-KDExOnByaXZhdGUta2V5KDM6ZHNhKDE6cDEyOToArHGqWD0rP0Nn/c3nYELTD4m1
-gqR7f2+l1ZUMdHcweYwn/fVjaJKmbR+9GzeHWP398FWYs5mCU1DIfrZLF0nJnAJ6
-WRnN9TL+oub1BqqLvCmDSngRuZZ2gUX8DVmD8xTsPnDnG74QDUnvtnpDIAs32sg5
-dnusstrriXD8xXgt0g8pKDE6cTIxOgC449htJbbp5rkJHvBDs4YxEIkk5ykoMTpn
-MTI4Ol+ITxpSMOT5R67Bu4XWoYU7nVeYURpb6LJ8LK2CV7ygECwFdRFdukiGFB+a
-TP8nF6xtuXalaBuerkKp4QXVKqOIkp7MWN2TAOOg9eERHPT//whryf49meNYMPLv
-KAe60udHY76Glm+Zso+24WnEwXX2od1PHVV3CItWRb7YmhgGKSgxOnkxMjg6AgXt
-40h2lpiIHTjbu6fiCBzbr5j2eQX3cNoydkRphJ66bqD+DsPW/Ag0WBCQxgRaLgMr
-db64fQT+fyjbTBLbC8ytt5hpCbm/q5x3TTXDAUNjoB3CnA/tQItBy7qqq/A0d3FZ
-grr6AixK58uZ4wauy8LRZCph67UZ8akcgwJkmVkpKDE6eDIwOn/Y1rjZASGMK9IG
-b1y/ZDKT0zkTKSkp
-=muRa
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc b/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc
deleted file mode 100644 (file)
index 7083673..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-S2V5OiAocHJpdmF0ZS1rZXkgKGVsZyAocCAjMDBDQ0Q4QjFGOURBQzc0RDgwOEND
-NTJGMEQ4OTQ2NERBNTU0QzY5RDY3RjMKIDMyM0M0MkE5NUM5OTYyREY0MjEyNkVD
-MEUwOTcxRjQ5QjgxMTUyOUE2QTJBRTlGMEFERUI4MzlBNjM0NjE1Q0Q1NkZBNTQK
-IEY1QTBCN0VGMjVBMEUyRkU4NDNGQTJFNkUwMjFDQUI0MTE5RTYwMzk0QzlENkEz
-RjdBRDRGNTc3OTZEMzY2NjlBNTEyNjYKIEMyN0E4RDFDNUE2QjQxNDFENUM4MzFF
-ODQ1NDFGM0M4MTFFODkwNzg5ODAzMzgyOTVGODJCN0Y3RkQ0MzMzRUZEOTMzMTIK
-IEYyQUIjKShnICMwNiMpKHkgIzM3NzNBNkQ5RUM4ODlENzZFMzI0RDZFNUVDMjFC
-RDQ1Njk5ODMxQUU0RkQwQUUwMzc4MjAKIDVCQUU1QjhDRTg1RkFEQUJEN0U2QjdD
-NzMwMjVDQjNENzMwRDVDNTgyOTAzNEQ3NkJFMDg1NUMyRTlGRjdBNDkyM0VGRkEK
-IEYxNkE5NjY2OTQ0REJDNjI5NDgzOEZDM0YwOUZGOTY0QThEMDIzQ0I4RUJBMzMy
-RkIwNTFFQTAyODIwRUU2MTIwRkZCRTYKIDJCMzZBMjAyQjNDNzUyRjlEQTc2QjJF
-QzExQTY3RDJFMzVFNjZFQzEwNjM1ODdCMjI1MDBFOEE0NkQxNTdCNzUjKSh4ICMK
-IDY5MTVDNkNFRDI1ODE0M0Y4OTM3QjEzMzVGNDg4N0YwMDQyQjdDNjMwMDUzOThG
-OTM5NkJCODUzMjM4Q0I2IykpKQo=
-=6fkh
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/pubring.kbx.asc b/tests/migrations/extended-private-key-format.gpghome/pubring.kbx.asc
deleted file mode 100644 (file)
index 5012371..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-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
-dYeJLGB5MYPnSPwADYVfNtLxsKZESLA=
-=tULv
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/trustdb.gpg.asc b/tests/migrations/extended-private-key-format.gpghome/trustdb.gpg.asc
deleted file mode 100644 (file)
index f4d354d..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-AWdwZwMDAQUBAgAAVxi2IwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-=eBUi
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.test b/tests/migrations/extended-private-key-format.test
deleted file mode 100755 (executable)
index 9c373e8..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/sh
-# Copyright 2016 g10 Code GmbH
-#
-# This file is free software; as a special exception the author gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.  This file is
-# distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY, to the extent permitted by law; without even the implied
-# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-if [ -z "$srcdir" ]; then
-   echo "not called from make" >&2
-   exit 1
-fi
-
-unset GNUPGHOME
-set -e
-
-# (We may not use a relative name for gpg-agent.)
-GPG_AGENT="$(cd ../../agent && /bin/pwd)/gpg-agent"
-GPG="../../g10/gpg --no-permission-warning --no-greeting --no-secmem-warning
---batch --agent-program=${GPG_AGENT}|--debug-quick-random"
-
-TEST="extended-private-key-format"
-
-setup_home()
-{
-    XGNUPGHOME="`mktemp -d`"
-    mkdir -p "$XGNUPGHOME/private-keys-v1.d"
-    for F in $srcdir/$TEST.gpghome/*.asc; do
-       $GPG --dearmor <"$F" >"$XGNUPGHOME/`basename $F .asc`"
-    done
-    for F in $srcdir/$TEST.gpghome/private-keys-v1.d/*.asc; do
-       $GPG --dearmor <"$F" >"$XGNUPGHOME/private-keys-v1.d/`basename $F .asc`"
-    done
-    chmod go-rwx $XGNUPGHOME/* $XGNUPGHOME/*/*
-    export GNUPGHOME="$XGNUPGHOME"
-}
-
-cleanup_home()
-{
-    rm -rf -- "$XGNUPGHOME"
-}
-
-assert_keys_usable()
-{
-    for KEY in C40FDECF ECABF51D; do
-       $GPG --list-secret-keys $KEY >/dev/null
-    done
-}
-
-setup_home
-assert_keys_usable
-cleanup_home
-
-
-# XXX try changing a key, and check that the format is not changed.
diff --git a/tests/migrations/from-classic.gpghome/pubring.gpg.asc b/tests/migrations/from-classic.gpghome/pubring.gpg.asc
deleted file mode 100644 (file)
index ecdfddc..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-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
-gBm4voMrZ05pAO2hFJbaIHWHibACAAM=
-=fphx
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/from-classic.gpghome/secring.gpg.asc b/tests/migrations/from-classic.gpghome/secring.gpg.asc
deleted file mode 100644 (file)
index 6aa367a..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-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
-=QqWQ
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/from-classic.gpghome/trustdb.gpg.asc b/tests/migrations/from-classic.gpghome/trustdb.gpg.asc
deleted file mode 100644 (file)
index d4ab65d..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
------BEGIN PGP ARMORED FILE-----
-Version: GnuPG v2
-Comment: Use "gpg --dearmor" for unpacking
-
-AWdwZwMDAQUBAgAAVxdnIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-=XUWW
------END PGP ARMORED FILE-----
diff --git a/tests/migrations/from-classic.scm b/tests/migrations/from-classic.scm
new file mode 100755 (executable)
index 0000000..2128532
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "common.scm"))
+
+(define src-tarball (in-srcdir "from-classic.tar.asc"))
+
+(define (setup)
+  (untar-armored src-tarball)
+  (setenv "GNUPGHOME" (getcwd) #t))
+
+(define (trigger-migration)
+  (call-check `(,@GPG --list-secret-keys)))
+
+(define (assert-migrated)
+  (unless (file-exists? ".gpg-v21-migrated")
+         (error "Not migrated"))
+
+  (for-each
+   (lambda (keyid)
+     (catch (error "Key not found:" keyid)
+           (call-check `(,@GPG --list-secret-keys ,keyid))))
+   '("D74C5F22" "C40FDECF" "ECABF51D")))
+
+(info "Testing a clean migration ...")
+(with-temporary-working-directory
+ (setup)
+ (trigger-migration)
+ (assert-migrated))
+
+(info "Testing a migration with existing private-keys-v1.d ...")
+(with-temporary-working-directory
+ (setup)
+ (mkdir "private-keys-v1.d" "-rwx")
+ (trigger-migration)
+ (assert-migrated))
+
+(info "Testing a migration with existing but weird private-keys-v1.d ...")
+(with-temporary-working-directory
+ (setup)
+ (mkdir "private-keys-v1.d" "")
+ (trigger-migration)
+ (assert-migrated))
+
+;; XXX Check a case where the migration fails.
diff --git a/tests/migrations/from-classic.tar.asc b/tests/migrations/from-classic.tar.asc
new file mode 100644 (file)
index 0000000..f35637d
--- /dev/null
@@ -0,0 +1,209 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+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
+AxUCAwMWAgECHgECF4AACgkQ0SC2Juyr9R1qQwP/bCDX1WGk1u0zkKJWJ/VXnuH3
+jk6ZevkuHZICwjlqAxv1de5P3Jeya/4kPmEQTotEv3xcDAZ+9pBL3TrZolAKhxkB
+Z08l4QSy76kyf8hB0eoZ2Svs7LrGPBJr6CHX0kyDiapHgAhBKQq9GhNKpIAZuL6D
+K2dOaQDtoRSW2iB1h4mwAgAA9gGehrd8xqenTd5nmLxvBiIiLxYmZimDq7eP17AJ
+z4V3rWzdt7zt3Scarg/bMDvKYcEdruoou/PZ214w+rzssr+1nKIFFUExwvaSUKzp
+A1/WjMYlVh7779qNhTlP5yWp8C/0DeCdLC9+srS6KoZ0cnVzdGRiLmdwZwAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDY0NAAwMDAx
+NzUwADAwMDE3NTAAMDAwMDAwMDIyNjAAMTI3MzY3MjQ2MTcAMDEzNjI3ACAwAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AHVzdGFyADAwdGV5dGhvb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ZXl0aG9v
+bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAFncGcDAwEFAQIAAFcXZyEAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAEKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+=nYpX
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/from-classic.test b/tests/migrations/from-classic.test
deleted file mode 100755 (executable)
index 9b81d45..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/sh
-# Copyright 2016 g10 Code GmbH
-#
-# This file is free software; as a special exception the author gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.  This file is
-# distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY, to the extent permitted by law; without even the implied
-# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-if [ -z "$srcdir" ]; then
-   echo "not called from make" >&2
-   exit 1
-fi
-
-unset GNUPGHOME
-set -e
-
-# (We may not use a relative name for gpg-agent.)
-GPG_AGENT="$(cd ../../agent && /bin/pwd)/gpg-agent"
-GPG="../../g10/gpg --no-permission-warning --no-greeting --no-secmem-warning
---batch --agent-program=${GPG_AGENT}|--debug-quick-random"
-
-TEST="from-classic"
-
-setup_home()
-{
-    XGNUPGHOME="`mktemp -d`"
-    rm -rf -- scratch
-    mkdir -p "$XGNUPGHOME"
-    for F in $srcdir/$TEST.gpghome/*.asc; do
-       $GPG --dearmor <"$F" >"$XGNUPGHOME/`basename $F .asc`"
-    done
-    chmod go-rwx $XGNUPGHOME/*
-    export GNUPGHOME="$XGNUPGHOME"
-}
-
-cleanup_home()
-{
-    rm -rf -- "$XGNUPGHOME"
-}
-
-trigger_migration()
-{
-    $GPG --list-secret-keys >/dev/null 2>&1
-}
-
-assert_migrated()
-{
-    test -f $GNUPGHOME/.gpg-v21-migrated
-
-    for KEY in D74C5F22 C40FDECF ECABF51D; do
-       $GPG --list-secret-keys $KEY >/dev/null
-    done
-}
-
-setup_home
-trigger_migration
-assert_migrated
-cleanup_home
-
-# Test with an existing private-keys-v1.d.
-setup_home
-mkdir "$GNUPGHOME/private-keys-v1.d"
-trigger_migration
-assert_migrated
-cleanup_home
-
-# Test with an existing private-keys-v1.d with weird permissions.
-setup_home
-mkdir "$GNUPGHOME/private-keys-v1.d"
-chmod 0 "$GNUPGHOME/private-keys-v1.d"
-trigger_migration
-assert_migrated
-cleanup_home
-
-# XXX Check a case where the migration fails.
diff --git a/tests/openpgp/4gb-packet.scm b/tests/openpgp/4gb-packet.scm
new file mode 100755 (executable)
index 0000000..8b2fcd6
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+;; GnuPG through 2.1.7 would incorrect mark packets whose size is
+;; 2^32-1 as invalid and exit with status code 2.
+
+(load (with-path "defs.scm"))
+
+(if (= 0 (call `(,@GPG --list-packets ,(in-srcdir "4gb-packet.asc"))))
+  (info "Can parse 4GB packets.")
+  (error "Failed to parse 4GB packet."))
index bb1047d..012a3f2 100644 (file)
@@ -22,7 +22,8 @@
 # Programs required before we can run these tests.
 required_pgms = ../../g10/gpg$(EXEEXT) ../../agent/gpg-agent$(EXEEXT) \
                 ../../tools/gpg-connect-agent$(EXEEXT) \
-               ../../tools/mk-tdata$(EXEEXT)
+               ../../tools/mk-tdata$(EXEEXT) \
+               ../gpgscm/gpgscm$(EXEEXT)
 
 AM_CPPFLAGS = -I$(top_srcdir)/common
 include $(top_srcdir)/am/cmacros.am
@@ -33,32 +34,54 @@ noinst_PROGRAMS = fake-pinentry
 
 fake_pinentry_SOURCES = fake-pinentry.c
 
-TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO= LC_ALL=C
+TMP ?= /tmp
 
-if SQLITE3
-sqlite3_dependent_tests = tofu.test
-else
-sqlite3_dependent_tests =
-endif
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO= LC_ALL=C \
+       EXEEXT=$(EXEEXT) \
+       PATH=../gpgscm:$(PATH) \
+       TMP=$(TMP) \
+       objdir=$(abs_top_builddir) \
+       GPGSCM_PATH=$(top_srcdir)/tests/gpgscm:$(top_srcdir)/tests/openpgp
 
-# Note: version.test needs to be the first test to run and finish.test
+# Note: setup.scm needs to be the first test to run and finish.scm
 # the last one
-TESTS = version.test mds.test \
-       decrypt.test decrypt-dsa.test \
-       sigs.test sigs-dsa.test \
-       encrypt.test encrypt-dsa.test  \
-       seat.test clearsig.test encryptp.test detach.test \
-       armsigs.test armencrypt.test armencryptp.test \
-       signencrypt.test signencrypt-dsa.test \
-       armsignencrypt.test armdetach.test \
-       armdetachm.test detachm.test genkey1024.test \
-       conventional.test conventional-mdc.test \
-       multisig.test verify.test armor.test \
-       import.test ecc.test 4gb-packet.test \
-       $(sqlite3_dependent_tests) \
-       gpgtar.test use-exact-key.test default-key.test \
-       export.test \
-       finish.test
+TESTS = setup.scm \
+       version.scm \
+       mds.scm \
+       decrypt.scm \
+       decrypt-dsa.scm \
+       sigs.scm \
+       sigs-dsa.scm \
+       encrypt.scm \
+       encrypt-dsa.scm \
+       seat.scm \
+       clearsig.scm \
+       encryptp.scm \
+       detach.scm \
+       detachm.scm \
+       armsigs.scm \
+       armencrypt.scm \
+       armencryptp.scm \
+       signencrypt.scm \
+       signencrypt-dsa.scm \
+       armsignencrypt.scm \
+       armdetach.scm \
+       armdetachm.scm \
+       genkey1024.scm \
+       conventional.scm \
+       conventional-mdc.scm \
+       multisig.scm \
+       verify.scm \
+       armor.scm \
+       import.scm \
+       ecc.scm \
+       4gb-packet.scm \
+       tofu.scm \
+       gpgtar.scm \
+       use-exact-key.scm \
+       default-key.scm \
+       export.scm \
+       finish.scm
 
 
 TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \
@@ -98,10 +121,14 @@ priv_keys = privkeys/50B2D4FA4122C212611048BC5FC31BD44393626E.asc \
            privkeys/1DF48228FEFF3EC2481B106E0ACA8C465C662CC5.asc \
            privkeys/A2832820DC9F40751BDCD375BB0945BA33EC6B4C.asc \
            privkeys/ADE710D74409777B7729A7653373D820F67892E0.asc \
-           privkeys/CEFC51AF91F68A2904FBFF62C4F075A4785B803F.asc
-
-
-sample_keys = samplekeys/ecc-sample-1-pub.asc \
+           privkeys/CEFC51AF91F68A2904FBFF62C4F075A4785B803F.asc \
+            privkeys/1E28F20E41B54C2D1234D896096495FF57E08D18.asc \
+            privkeys/EB33B687EB8581AB64D04852A54453E85F3DF62D.asc \
+           privkeys/C6A6390E9388CDBAD71EAEA698233FE5E04F001E.asc \
+           privkeys/D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3.asc
+
+sample_keys = samplekeys/README \
+              samplekeys/ecc-sample-1-pub.asc \
               samplekeys/ecc-sample-2-pub.asc \
               samplekeys/ecc-sample-3-pub.asc \
               samplekeys/ecc-sample-1-sec.asc \
@@ -114,10 +141,14 @@ sample_keys = samplekeys/ecc-sample-1-pub.asc \
              samplekeys/whats-new-in-2.1.asc \
              samplekeys/e2e-p256-1-clr.asc \
              samplekeys/e2e-p256-1-prt.asc \
-             samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc
-
-EXTRA_DIST = defs.inc pinentry.sh $(TESTS) $(TEST_FILES) ChangeLog-2011 \
-            mkdemodirs signdemokey $(priv_keys) $(sample_keys)
+             samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc \
+              samplekeys/rsa-rsa-sample-1.asc \
+              samplekeys/ed25519-cv25519-sample-1.asc \
+             samplekeys/silent-running.asc
+
+EXTRA_DIST = defs.inc defs.scm pinentry.sh $(TESTS) $(TEST_FILES) \
+            mkdemodirs signdemokey $(priv_keys) $(sample_keys)   \
+            ChangeLog-2011
 
 CLEANFILES = prepared.stamp x y yy z out err  $(data_files) \
             plain-1 plain-2 plain-3 trustdb.gpg *.lock .\#lk* \
diff --git a/tests/openpgp/README b/tests/openpgp/README
new file mode 100644 (file)
index 0000000..1f8654b
--- /dev/null
@@ -0,0 +1,161 @@
+#                                   Emacs, this is an -*- org -*- file.
+
+* How to run the test suite
+** using the legacy driver
+On POSIX you can just use
+
+  $ make -C tests/openpgp check
+
+or
+
+  $ make -C tests/openpgp check TESTS="setup.scm your-test.scm finish.scm"
+
+as before.
+** using the Scheme driver
+This is a bit tricky because one needs to manually set some
+environment variables.  We should make that easier.  See discussion
+below.  From your build directory, do:
+
+  obj $ srcdir=<path to>/tests/openpgp \
+        GPGSCM_PATH=<path to>/tests/gpgscm:<path to>/tests/openpgp \
+        $(pwd)/tests/gpgscm/gpgscm [gpgscm args] \
+        run-tests.scm [test suite runner args]
+
+*** Arguments supported by the test suite runner
+The test suite runner supports four modes of operation,
+{sequential,parallel}x{isolated,shared}.  You can select the mode of
+operation using a combination of the flags --parallel, --sequential,
+--shared, and --isolated.
+
+By default the tests are run in sequential order, each one in a clean
+environment.
+
+You can specify the tests to run as positional arguments relative to
+srcdir (e.g. just 'version.scm').  By default all tests listed in
+run-tests.scm are executed.  Note that you do not have to specify
+setup.scm and finish.scm, they are executed implicitly.
+
+The test suite runner can be executed in any location that the current
+user can write to.  It will create temporary files and directories,
+but will in general clean up all of them.
+*** Discussion of the various environment variables
+**** srcdir
+Must be set to the source of the openpgp test suite.  Used to locate
+data files.
+**** GPGSCM_PATH
+Used to locate the Scheme library as well as code used by the test
+suite.
+**** BIN_PREFIX
+The test suite does not hardcode any paths to tools.  If set it is
+used to locate the tools to test, otherwise the test suite assumes to
+be run from the build directory.
+**** MKTDATA and GPG_PRESET_PASSPHRASE
+These two tools are not installed by 'make install', hence we need to
+explicitly override their position.  In fact, the location of any tool
+used by the test suite can be overridden this way.  See defs.scm.
+**** argv[0]
+run-tests.scm depends on being able to re-exec gpgscm.  It uses
+argv[0] for that.  Therefore you must use an absolute path to invoke
+gpgscm.
+* How to write tests
+gpgscm provides a number of functions to aid you in writing tests, as
+well as bindings to process management abstractions provided by GnuPG.
+For the Scheme environment provided by TinySCHEME, see the TinySCHEME
+manual that is included in tests/gpgscm/Manual.txt.
+
+For a quick start, please have a look at various tests that are
+already implemented, e.g. 'encrypt.scm'.
+** The test framework
+The functions info, error, and skip display their first argument and
+flush the output buffers.  error and skip will also terminate the
+process, signaling that the test failed or should be skipped.
+
+(for-each-p msg proc list) will display msg, and call proc with each
+element of list while displaying the progress appropriately.
+for-each-p' is similar, but accepts another callback before the 'list'
+argument to format each item.  for-each-p can be safely nested, and
+the inner progress indicator will be abbreviated using '.'.
+** Temporary files
+(lettmp <bindings> <body>) will create and delete temporary files that
+you can use in <body>.  (with-temporary-working-directory <body>) will
+create a temporary director, change to that, and clean it up after
+executing <body>).
+
+make-temporary-file will create a temporary file.  You can optionally
+provide an argument to that function that will serve as tag so you can
+distinguish the files for debugging.  remove-temporary-file will
+delete a file created using make-temporary-file.
+
+** Monadic transformer and pipe support
+Tests often perform sequential transformations on files, or connect
+processes using pipes.  To aid you in this, the test framework
+provides two monadic data structures.
+
+(Currently, the implementation mashes the 'bind' operation together
+with the application of the monad.  Also, there is no 'return'
+operation.  I guess all of that could be implemented on top of
+call/cc, but it isn't at the moment.)
+*** pipe
+The pipe monad constructs pipe lines.  It consists of a function
+pipe:do that binds the functions together and manages the execution of
+the child processes, a family of functions that act as sources, a
+function to spawn processes, and a family of functions acting as
+sinks.
+
+Sources are pipe:open, pipe:defer, pipe:echo.  To spawn a process use
+pipe:spawn, or the convenience function pipe:gpg.  To sink the data
+use pipe:splice, or pipe:write-to.
+
+Example:
+
+  (pipe:do
+    (pipe:echo "3\n1\n2\n")
+    (pipe:spawn '("/usr/bin/sort"))
+    (pipe:write-to "sorted" (logior O_WRONLY O_CREAT) #o600))
+
+Caveats: Due to the single-threaded nature of gpgscm you cannot use
+both a source and sink that is implemented in Scheme.  pipe:defer and
+pipe:echo are executing in gpgscm, and so does pipe:splice.
+*** tr
+The transformer monad describes sequential file transformations.
+
+There is one source function, tr:open.  To describe a transformation
+using some process, use tr:spawn, tr:gpg, or tr:pipe-do.  There are
+several sinks, although sink is not quite the right term, because the
+data is not consumed, and hence one can use them at any position.  The
+"sinks" are tr:write-to, tr:call-with-content, tr:assert-identity, and
+tr:assert-weak-identity.
+
+A somewhat contrived example demonstrating many functions is:
+
+  (tr:do
+    (tr:pipe-do
+      (pipe:echo "3\n1\n2\n")
+      (pipe:spawn '("/usr/bin/sort")))
+    (tr:write-to "reference")
+    (tr:call-with-content
+     (lambda (c)
+       (echo "currently, c contains" (string-length c) "bytes")))
+    (tr:spawn "" '("/usr/bin/gcc" -x c "-E" -o **out** **in**))
+    (tr:pipe-do
+      (pipe:spawn '("/bin/grep" -v "#")))
+    (tr:assert-identity "reference"))
+
+Caveats: As a convenience, gpgscm allows one to specify command line
+arguments as Scheme symbols.  Scheme symbols, however, are
+case-insensitive, and get converted to lower case.  Therefore, the -E
+argument must be given as a string in the example above.  Similarly,
+you need to quote numerical values.
+** Process management
+If you just need to execute a single command, there is (call-with-fds
+cmdline infd outfd errfd) which executes cmdline with the given file
+descriptors bound to it, and waits for its completion returning the
+status code.  There is (call cmdline) which is similar, but calls the
+command with a closed stdin, connecting stdout and stderr to stderr if
+gpgscm is executed with --verbose.  (call-check cmdline) raises an
+exception if the command does not return 0.
+
+(call-popen cmdline input) calls a command, writes input to its stdin,
+and returns any output from stdout, or raises an exception containing
+stderr on failure.
+* Sample messages
diff --git a/tests/openpgp/armdetach.scm b/tests/openpgp/armdetach.scm
new file mode 100755 (executable)
index 0000000..69e09d8
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking armored detached signatures"
+ (lambda (source)
+   (lettmp (tmp)
+     (call-popen `(,@GPG --yes --passphrase-fd "0" -sab
+                        --output ,tmp ,source ) usrpass1)
+     (pipe:do
+      (pipe:open source (logior O_RDONLY O_BINARY))
+      (pipe:spawn `(,@GPG --yes ,tmp)))))
+ (append plain-files data-files))
diff --git a/tests/openpgp/armdetachm.scm b/tests/openpgp/armdetachm.scm
new file mode 100755 (executable)
index 0000000..618f7aa
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define files (append plain-files data-files))
+
+(info "Checking armored detached signatures of multiple files")
+(lettmp (tmp)
+  (call-popen `(,@GPG --yes --passphrase-fd "0" -sab
+                     --output ,tmp ,@files) usrpass1)
+  (pipe:do
+   (pipe:defer (lambda (sink)
+                (for-each (lambda (file)
+                            (pipe:do
+                             (pipe:open file (logior O_RDONLY O_BINARY))
+                             (pipe:splice sink)))
+                          files)))
+   (pipe:spawn `(,@GPG --yes ,tmp))))
diff --git a/tests/openpgp/armencrypt.scm b/tests/openpgp/armencrypt.scm
new file mode 100755 (executable)
index 0000000..b0cf099
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking armored encryption"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg usrpass1 `(--yes --passphrase-fd "0" -ea --recipient ,usrname2))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
diff --git a/tests/openpgp/armencryptp.scm b/tests/openpgp/armencryptp.scm
new file mode 100755 (executable)
index 0000000..7555ce9
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking armored encryption and decryption using pipes"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:pipe-do
+     (pipe:gpg `(--yes -ea --recipient ,usrname2))
+     (pipe:gpg '(--yes)))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
diff --git a/tests/openpgp/armor.scm b/tests/openpgp/armor.scm
new file mode 100755 (executable)
index 0000000..5b4ea14
--- /dev/null
@@ -0,0 +1,766 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define armored_key_8192 "-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: SKS 1.0.9
+
+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
+=oXxa
+-----END PGP PUBLIC KEY BLOCK-----
+")
+
+;; Bug solved 2005-04-07:
+;; Try importing the attached key file.  As the key is exactly 8192
+;; bytes long, radix64_read is called twice - the first time to read
+;; the 8192 bytes, and then once again, to handle the pad '=' on the
+;; last four character radix64 block '0uI='.  gpg bails out with
+;;  gpg: [don't know]: invalid packet (ctb=2d)
+;; On a read for only the = sign, radix64_read returns -1 for EOF.
+;; This causes the iobuf code to pop the armor filter and thus the next
+;; byte read is the '-' from the END header line, causing an error.
+(info "Checking armored_key_8192")
+(pipe:do
+ (pipe:echo armored_key_8192)
+ (pipe:gpg '(--import)))
+
+(define nopad_armored_msg "-----BEGIN PGP MESSAGE-----
+Version: GnuPG v1.4.11-svn5139 (GNU/Linux)
+
+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
+jnOKMUrdbDkbYM+ojXZ18/4WPKtaxf6lTLrh3m5CJ1V8slRJp0Jes74aDQf/OXqo
+QgqVrI2wnl1klGwn06bhVaymdk0hMkxAfeHBGZIQ4BMMZ3aLuVWjAcBH/HP1tVQ4
+IG7MHRnm81yVNgA6yAuZZIPQwxDWVko7rRm/DnsJcpKfL0nZHoF+bJ6q4Rd6Dey1
+S96L4PDmXseFkVZOH/7dNWyKuvSA/MmthkN14lWJiYJebaXb7oZG3XDC70o7bG6Y
+mtGOrOwVthFereg1Ii98ZA4nKgqeu2paMju/t03hQXHY5iqyV9ax0A3B0rdivz4U
+VbqCcO7pGNb/Ki3gGc3hfVw9YXnR7E+tra19eE7UM7o+YlunKF1Q5dJaLKY1z3L9
+3UAJmXG/sZcLqrDn9zHfb/YxqbyIkM7VIU2kKztWCCNiNKgLQsIoVzK4sbS2LVDI
+grmvZg+Q7EkwxZ1FXeBGJmsiyjKYPU3PI8ZBU1MXjwTjtnQRuBSxh+Ok9glPeE+1
+rUDdlVoogUGgPAvLV3BM43E/Q5VE+X04KvPNKINvvS1nZpGKyyy1MayOfstc7Hsw
+W/RgllTEd7VW5jgZKg7YyA8r8cUjMqE7zewrq6MtkoFk6ZVslWxfoADBW3ivwdwe
+I4XwNboOgBx77qxf95aHRRdqWZa0JF8zvK5BH6EpBI29hlJU4leax696ACA7QIIM
+Rpc+ulkvHsNxsUlrUut9AXoob0MqDJRmZvU4gSVivHjvKLEIlymJw4pLbMWhcrNa
+v94TExP21Fy/zYcWiZT2nCX6qZVXTcUcQGIrBTWDbR8bxKll4FNo/2zmelyFmeXt
+iH+Zp2EwFAUELsrxx9plNd5WceyU9VnZoeucNFd2QFl7lV9KL8AlQaaMdsYOt27m
+8j7iNBID4HtCYM0xLwE/5uqVQPxX6qzPPZc66MSRIi8ZHZPFvVilFVzFyZSrq5Lo
+ojQQmAycQGOzx7dwx7vi9SeTrBRY2PK3WVurcLiRxM+2u9vjlxigwimpnK3VU1dh
+GDoPghB3O34bfiV5GndcnPDLJxsSGWz2z2WiyCFgCkVp3shHUN5c2PLWDIOf/Ejz
+LzNJXFKjO6/6ZGpMmGf6bZCa9MBnvXMNic9/k0lmtbgj8SS+2//gko1EDa/Gpaqo
+J2xgEuHLvp9KQABWt9VRI+tNUJQCS/Jq10ZiT1TzhczyJEqbtVDOo0l5A5sMV0PO
+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
+=3akT
+-----END PGP MESSAGE-----
+
+")
+
+(define alpha_seckey "-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.8 (GNU/Linux)
+
+lQHhBDbjjp4RBAC2ZbFDX0wmJI8yLDYQdIiZeAuHLmfyHsqXaLGUMZtWiAvn/hNp
+ctwahmzKm5oXinHUvUkLOQ0s8rOlu15nhw4azc30rTP1LsIkn5zORNnFdgYC6RKy
+hOeim/63+/yGtdnTm49lVfaCqwsEmBCEkXaeWDGq+ie1b89J89T6n/JquwCgoQkj
+VeVGG+B/SzJ6+yifdHWQVkcD/RXDyLXX4+WHGP2aet51XlKojWGwsZmc9LPPYhwU
+/RcUO7ce1QQb0XFlUVFBhY0JQpM/ty/kNi+aGWFzigbQ+HAWZkUvA8+VIAVneN+p
++SHhGIyLTXKpAYTq46AwvllZ5Cpvf02Cp/+W1aVyA0qnBWMyeIxXmR9HOi6lxxn5
+cjajA/9VZufOXWqCXkBvz4Oy3Q5FbjQQ0/+ty8rDn8OTaiPi41FyUnEi6LO+qyBS
+09FjnZj++PkcRcXW99SNxmEJRY7MuNHt5wIvEH2jNEOJ9lszzZFBDbuwsjXHK35+
+lPbGEy69xCP26iEafysKKbRXJhE1C+tk8SnK+Gm62sivmK/5av4CAwKcF1Qep+Pf
+ssOqtJhr+klruUBf55onBJi4vkk0gK3m32p/05YB2bbMURGz8R4JxUZfUxjdDk73
+LaNYRbQpQWxwaGEgVGVzdCAoZGVtbyBrZXkpIDxhbHBoYUBleGFtcGxlLm5ldD6I
+VQQTEQIAFQUCNuOOngMLCgMDFQMCAxYCAQIXgAAKCRAtcnzHaGl3NDl4AJ4rouHB
++LpCkNi5C59jHEa1kbANzACgmddtrNSj1yPyTCwUwRghPUomECS0EEFsaWNlIChk
+ZW1vIGtleSmIVQQTEQIAFQUCNuO2qwMLCgMDFQMCAxYCAQIXgAAKCRAtcnzHaGl3
+NCeMAJ9MeUVrago5Jc6PdwdeN5OMwby37QCghW65cZTQlD1bBlIq/QM8bz9AN4G0
+J0FsZmEgVGVzdCAoZGVtbyBrZXkpIDxhbGZhQGV4YW1wbGUubmV0PohVBBMRAgAV
+BQI247hYAwsKAwMVAwIDFgIBAheAAAoJEC1yfMdoaXc0t8IAoJPwa6j+Vm5Vi3Nv
+uo8JZri4PJ/DAJ9dqbmaJdB8FdJnHfGh1rXK3y/Jcp0BuAQ2448PEAQAnI3XH1f0
+uyN9fZnw72zsHMw706g7EW29nD4UDQG4OzRZViSrUa5n39eI7QrfTO+1meVvs0y8
+F/PvFst5jH68rPLnGSrXz4sTl1T4cop1FBkquvCAKwPLy0lE7jjtCyItOSwIOo8x
+oTfY4JEEXmcqsbm+KHv9yYSF/YK4Cf7bIzcAAwcD/Rnl5jKxoucDA96pD2829TKs
+LFQSau+Xiy8bvOSSDdlyABsOkNBSaeKO3eAQEKgDM7dzjVNTnAlpQ0EQ8Y9Z8pxO
+WYEQYlaMrnRBC4DZ2IadzEhLlIOz5BVp/jfhrr8oVVBwKZXsrz9PZLz+e4Yn+siU
+Uvlei9boD9L2ZgSOHakP/gIDApwXVB6n49+yw6e5k2VJBGTFDkQbxpgi4oslePpT
+7Tc2qjAke4zO8JHkgKSokEgnMpMz412q9otFX/3qC5MpPG5P8f4r00Kfy9Am/thk
+ri01WTIUqF8L/VZXJxLKVoRAabSXudG0eavfah14fN5/+Bw5i8vSHhc/xmQEKTya
+2X8Nt1F5zMrE1LAGVVCL9i/DUygnJYOZzAd1Ct0RJ4kFj7lOBICF2IWWiEYEGBEC
+AAYFAjbjjw8ACgkQLXJ8x2hpdzQgqQCgn81AaW8W/lyVwMh/UBeMuVMUb24An2uz
+wg7Md81a5RI3F2FG8747t9gX
+=VM1e
+-----END PGP PRIVATE KEY BLOCK-----
+")
+
+;; Bug 1179 solved 2010-05-12:
+;; It occured for messages of a multiple of the iobuf block size where
+;; the last line had no pad character.  Due to premature poppng of thea
+;; rmor filter gpg swalled the CRC line and passed the '-----END...'
+;; line on to the decryption layer.
+
+(info "Importing alpha_seckey")
+(pipe:do
+ (pipe:echo alpha_seckey)
+ (pipe:gpg '(--import)))
+
+(info "Checking for bug #1179")
+(tr:do
+ (tr:pipe-do
+  (pipe:echo nopad_armored_msg)
+  (pipe:gpg '())))
diff --git a/tests/openpgp/armsignencrypt.scm b/tests/openpgp/armsignencrypt.scm
new file mode 100755 (executable)
index 0000000..b84bfe4
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking armored signing and encryption"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg usrpass1 `(--yes --passphrase-fd "0" -sea --recipient ,usrname2))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
diff --git a/tests/openpgp/armsigs.scm b/tests/openpgp/armsigs.scm
new file mode 100755 (executable)
index 0000000..d897581
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking armored signatures"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg usrpass1 `(--yes --passphrase-fd "0" -sa --recipient ,usrname2))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
diff --git a/tests/openpgp/clearsig.scm b/tests/openpgp/clearsig.scm
new file mode 100755 (executable)
index 0000000..96b1b4c
--- /dev/null
@@ -0,0 +1,107 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define (check-signing args input)
+  (lambda (source sink)
+    (lettmp (signed)
+           (call-popen `(,@GPG --output ,signed --yes
+                               ,@args ,source) input)
+           (call-popen `(,@GPG --output ,sink --yes ,signed) ""))))
+
+(for-each-p
+ "Checking signing and verifying plain text messages"
+ (lambda (source)
+   ((if (equal? "plain-3" source)
+       ;; plain-3 does not end in a newline, and gpg will add one.
+       ;; Therefore, we merely check that the verification is ok.
+       check-execution
+       ;; Otherwise, we do check that we recover the original file.
+       check-identity)
+    source
+    (check-signing '(--passphrase-fd "0" --clearsign) usrpass1)))
+ (append plain-files '("plain-large")))
+
+;; The test vectors are lists of length three, containing
+;; - a string to be signed,
+;; - a flag indicating whether we verify that the exact message is
+;;   reconstructed (whitespace at the end is normalized for plain text
+;;   messages),
+;; - and a list of arguments to add to gpg when encoding
+;;   the string.
+
+(define :string car)
+(define :check-equality cadr)
+(define :options caddr)
+
+(define
+  vectors
+  '(;; one with long lines
+    ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyx
+
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+" #t ())
+
+    ;; one with only one long line
+    ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyx
+" #t ())
+
+    ;; and one with an empty body
+    ("" #f ())
+
+    ;; and one with one empty line at the end
+    ("line 1
+line 2
+line 3
+there is a blank line after this
+
+" #t ())
+
+    ;; I think this file will be constructed wrong (gpg 0.9.3) but it
+    ;; should verify okay anyway.
+    ("this is a sig test
+ " #f ())
+
+    ;; check our special diff mode
+    ("--- mainproc.c   Tue Jun 27 09:28:11 2000
++++ mainproc.c~ Thu Jun  8 22:50:25 2000
+@@ -1190,16 +1190,13 @@
+               md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo);
+           }
+           /* ask for file and hash it */
+-          if( c->sigs_only ) {
++          if( c->sigs_only )
+               rc = hash_datafiles( c->mfx.md, NULL,
+                                    c->signed_data, c->sigfilename,
+                       n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 );
+" #t (--not-dash-escaped))))
+
+(let ((counter (make-counter)))
+  (for-each-p'
+   "Checking signing and verifying test vectors"
+   (lambda (vec)
+     (lettmp (tmp)
+       (with-output-to-file tmp (lambda () (display (:string vec))))
+       ((if (:check-equality vec) check-identity check-execution)
+       tmp
+       (check-signing `(--passphrase-fd "0" --clearsign ,@(:options vec))
+                      usrpass1))))
+   (lambda (vec) (counter))
+   vectors))
diff --git a/tests/openpgp/conventional-mdc.scm b/tests/openpgp/conventional-mdc.scm
new file mode 100755 (executable)
index 0000000..c524921
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define s2k '--s2k-count=65536)
+(define passphrase "Hier spricht HAL")
+
+(define (file-copy-n from to n)
+  (catch '() (unlink to))
+  (letfd ((source (open from (logior O_RDONLY O_BINARY)))
+         (sink (open to (logior O_WRONLY O_CREAT O_BINARY) #o600)))
+    (splice source sink n)))
+
+(define test-files
+  (map (lambda (size)
+        (let ((tmp (make-temporary-file
+                    (string-append "data-80000-" (number->string size)))))
+          (file-copy-n "data-80000" tmp size)
+          tmp))
+       '(0 1 2 3 9 10 11 19 20 21 22 23 39 40 41 8192 32000)))
+
+(for-each-p
+ "Checking conventional encryption with MDC"
+ (lambda (algo)
+   (for-each-p
+    ""
+    (lambda (source)
+      (tr:do
+       (tr:open source)
+       (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k
+                                 --force-mdc -c
+                                 --cipher-algo ,algo))
+       (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k))
+       (tr:assert-identity source)))
+    test-files))
+ all-cipher-algos)
+
+(for-each remove-temporary-file test-files)
+
+(for-each-p
+ "Checking sign+symencrypt"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+     (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k -cs))
+     (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k))
+     (tr:assert-identity source)))
+ (append plain-files data-files))
diff --git a/tests/openpgp/conventional.scm b/tests/openpgp/conventional.scm
new file mode 100755 (executable)
index 0000000..67e28e2
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define s2k '--s2k-count=65536)
+(define passphrase "Hier spricht HAL")
+
+(for-each-p
+ "Checking conventional encryption"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+     (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k -c))
+     (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k))
+     (tr:assert-identity source)))
+ '("plain-2" "data-32000"))
+
+(for-each-p
+ "Checking conventional encryption using a specific cipher"
+ (lambda (algo)
+   (for-each-p
+    ""
+    (lambda (source)
+      (tr:do
+       (tr:open source)
+       (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k -c
+                                 --cipher-algo ,algo))
+       (tr:gpg passphrase `(--yes --passphrase-fd "0" ,s2k))
+       (tr:assert-identity source)))
+    '("plain-1" "data-80000")))
+ all-cipher-algos)
diff --git a/tests/openpgp/decrypt-dsa.scm b/tests/openpgp/decrypt-dsa.scm
new file mode 100755 (executable)
index 0000000..b01a0f7
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking decryption of supplied DSA encrypted file"
+ (lambda (name)
+   (tr:do
+    (tr:open (in-srcdir (string-append name "-pgp.asc")))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity name)))
+ (list (car plain-files)))
diff --git a/tests/openpgp/decrypt.scm b/tests/openpgp/decrypt.scm
new file mode 100755 (executable)
index 0000000..ec0f8e7
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking decryption of supplied files"
+ (lambda (name)
+   (tr:do
+    (tr:open (in-srcdir (string-append name ".asc")))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity name)))
+ plain-files)
diff --git a/tests/openpgp/default-key.scm b/tests/openpgp/default-key.scm
new file mode 100755 (executable)
index 0000000..4433658
--- /dev/null
@@ -0,0 +1,76 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+;; Import the sample key
+;;
+;; pub   1024R/8BC90111 2015-12-02
+;;       Key fingerprint = E657 FB60 7BB4 F21C 90BB  6651 BC06 7AF2 8BC9 0111
+;; uid       [ultimate] Barrett Brown <barrett@example.org>
+;; sub   1024R/3E880CFF 2015-12-02 (encryption)
+;; sub   1024R/F5F77B83 2015-12-02 (signing)
+;; sub   1024R/45117079 2015-12-02 (encryption)
+;; sub   1024R/1EA97479 2015-12-02 (signing)
+
+(info "Importing public key.")
+(call-check
+ `(,(tool 'gpg) --import
+   ,(in-srcdir "samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc")))
+
+;; By default, the most recent, valid signing subkey (1EA97479).
+(for-each-p
+ "Checking that the most recent, valid signing subkey is used by default"
+ (lambda (keyid)
+   (tr:do
+     (tr:pipe-do
+      (pipe:defer (lambda (sink) (display "" (fdopen sink "w"))))
+      (pipe:gpg `(--default-key ,keyid -s))
+      (pipe:gpg '(--verify --status-fd=1)))
+     (tr:call-with-content
+      (lambda (c)
+       (unless (string-contains?
+                c "VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479")
+           (exit 1))))))
+ '("8BC90111" "3E880CFF" "F5F77B83" "45117079" "1EA97479"))
+
+;; But, if we request a particular signing key, we should get it.
+(for-each-p
+ "Checking that the most recent, valid encryption subkey is used by default"
+ (lambda (keyid)
+   (tr:do
+     (tr:pipe-do
+      (pipe:defer (lambda (sink) (display "" (fdopen sink "w"))))
+      ;; We need another recipient, because --encrypt-to-default-key is
+      ;; not considered a recipient and gpg doesn't encrypt without any
+      ;; recipients.
+      ;;
+      ;; Note: it doesn't matter whether we specify the primary key or
+      ;; a subkey: the newest encryption subkey will be used.
+      (pipe:gpg `(--default-key ,keyid --encrypt-to-default-key
+                               -r "439F02CA" -e))
+      (pipe:gpg '(--list-packets)))
+     (tr:call-with-content
+      (lambda (c)
+       (unless (any (lambda (line)
+                      (and (string-prefix? line ":pubkey enc packet:")
+                           (string-suffix? line "45117079")))
+                    (string-split c #\newline))
+           (exit 1))))))
+ '("8BC90111" "3E880CFF" "F5F77B83" "45117079" "1EA97479"))
diff --git a/tests/openpgp/defs.scm b/tests/openpgp/defs.scm
new file mode 100644 (file)
index 0000000..8ceffc8
--- /dev/null
@@ -0,0 +1,134 @@
+;; Common definitions for the OpenPGP test scripts.
+;;
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+;;
+;; Constants.
+;;
+
+(define usrname1 "one@example.com")
+(define usrpass1 "def")
+(define usrname2 "two@example.com")
+(define usrpass2 "")
+(define usrname3 "three@example.com")
+(define usrpass3 "")
+
+(define dsa-usrname1 "pgp5")
+;; we use the sub key because we do not yet have the logic to to derive
+;; the first encryption key from a keyblock (I guess) (Well of course
+;; we have this by now and the notation below will lookup the primary
+;; first and then search for the encryption subkey.)
+(define dsa-usrname2 "0xCB879DE9")
+
+(define key-file1 "samplekeys/rsa-rsa-sample-1.asc")
+(define key-file2 "samplekeys/ed25519-cv25519-sample-1.asc")
+
+(define plain-files '("plain-1" "plain-2" "plain-3"))
+(define data-files '("data-500" "data-9000" "data-32000" "data-80000"))
+(define exp-files '())
+
+(define (qualify executable)
+  (string-append executable (getenv "EXEEXT")))
+
+(define (getenv' key default)
+  (let ((value (getenv key)))
+    (if (string=? "" value)
+       default
+       value)))
+
+(define tools
+  '((gpg "GPG" "g10/gpg")
+    (gpg-agent "GPG_AGENT" "agent/gpg-agent")
+    (gpg-connect-agent "GPG_CONNECT_AGENT" "tools/gpg-connect-agent")
+    (gpgconf "GPGCONF" "tools/gpgconf")
+    (gpg-preset-passphrase "GPG_PRESET_PASSPHRASE"
+                          "agent/gpg-preset-passphrase")
+    (mktdata "MKTDATA" "tools/mk-tdata")
+    (gpgtar "GPGTAR" "tools/gpgtar")
+    (gpg-zip "GPGZIP" "tools/gpg-zip")))
+
+(define (tool which)
+  (let ((t (assoc which tools))
+       (prefix (getenv "BIN_PREFIX")))
+    (getenv' (cadr t)
+            (qualify (if (string=? prefix "")
+                         (string-append (getenv "objdir") "/" (caddr t))
+                         (string-append prefix "/" (basename (caddr t))))))))
+
+
+(define have-opt-always-trust
+  (string-contains? (call-popen `(,(tool 'gpg) --dump-options) "")
+                       "--always-trust"))
+
+(define GPG `(,(tool 'gpg) --no-permission-warning
+             ,@(if have-opt-always-trust '(--always-trust) '())))
+(define PINENTRY (string-append (getcwd) "/" (qualify "fake-pinentry")))
+
+(define (tr:gpg input args)
+  (tr:spawn input `(,@GPG --output **out** ,@args **in**)))
+
+(define (pipe:gpg args)
+  (pipe:spawn `(,@GPG --output - ,@args -)))
+
+(define (gpg-with-colons args)
+  (let ((s (call-popen `(,@GPG --with-colons ,@args) "")))
+    (map (lambda (line) (string-split line #\:))
+        (string-split s #\newline))))
+
+(define (get-config what)
+  (string-split (caddar (gpg-with-colons `(--list-config ,what))) #\;))
+
+(define all-pubkey-algos (get-config "pubkeyname"))
+(define all-hash-algos (get-config "digestname"))
+(define all-cipher-algos (get-config "ciphername"))
+
+(define (have-pubkey-algo? x)
+  (not (not (member x all-pubkey-algos))))
+(define (have-hash-algo? x)
+  (not (not (member x all-hash-algos))))
+(define (have-cipher-algo? x)
+  (not (not (member x all-cipher-algos))))
+
+(define (gpg-pipe args0 args1 errfd)
+  (lambda (source sink)
+    (let* ((p (pipe))
+          (task0 (spawn-process-fd `(,@GPG ,@args0)
+                  source (:write-end p) errfd))
+          (_ (close (:write-end p)))
+          (task1 (spawn-process-fd `(,@GPG ,@args1)
+                  (:read-end p) sink errfd)))
+      (close (:read-end p))
+      (wait-processes (list GPG GPG) (list task0 task1) #t))))
+
+(setenv "GPG_AGENT_INFO" "" #t)
+(setenv "GNUPGHOME" (getcwd) #t)
+
+;;
+;; GnuPG helper.
+;;
+
+;; Call GPG to obtain the hash sums.  Either specify an input file in
+;; ARGS, or an string in INPUT.  Returns a list of (<algo>
+;; "<hashsum>") lists.
+(define (gpg-hash-string args input)
+  (map
+   (lambda (line)
+     (let ((p (string-split line #\:)))
+       (list (string->number (cadr p)) (caddr p))))
+   (string-split
+    (call-popen `(,@GPG --with-colons ,@args) input) #\newline)))
diff --git a/tests/openpgp/detach.scm b/tests/openpgp/detach.scm
new file mode 100755 (executable)
index 0000000..375e922
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking detached signatures"
+ (lambda (source)
+   (lettmp (tmp)
+     (call-popen `(,@GPG --yes --passphrase-fd "0" -sb
+                        --output ,tmp ,source ) usrpass1)
+     (pipe:do
+      (pipe:open source (logior O_RDONLY O_BINARY))
+      (pipe:spawn `(,@GPG --yes ,tmp)))))
+ (append plain-files data-files))
diff --git a/tests/openpgp/detachm.scm b/tests/openpgp/detachm.scm
new file mode 100755 (executable)
index 0000000..a4ebce0
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define files (append plain-files data-files))
+
+(info "Checking detached signatures of multiple files")
+(lettmp (tmp)
+  (call-popen `(,@GPG --yes --passphrase-fd "0" -sb
+                     --output ,tmp ,@files) usrpass1)
+  (pipe:do
+   (pipe:defer (lambda (sink)
+                (for-each (lambda (file)
+                            (pipe:do
+                             (pipe:open file (logior O_RDONLY O_BINARY))
+                             (pipe:splice sink)))
+                          files)))
+   (pipe:spawn `(,@GPG --yes ,tmp))))
diff --git a/tests/openpgp/ecc.scm b/tests/openpgp/ecc.scm
new file mode 100755 (executable)
index 0000000..f2f3b7c
--- /dev/null
@@ -0,0 +1,249 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define keygrips '("8E06A180EFFE4C65B812150CAF19BF30C0689A4C"
+                  "E4403F3FD7A443FAC29FEF288FA0D20AC212851E"
+                  "0B7554421FFB14A06CB9F63FB49A85A58E97ABAC"
+                  "303ACC892C2D786C8A789677C0BE54DA8538F903"
+                  "9FE5C36985351524B6AFA19FDCBC1A3A750B6F5F"
+                  "145A52CC7ED3FD41C5B0A26BE220FEED36AF24DE"))
+(define mainkeyids '("BAA59D9C" "0F54719F" "45AF2FFE"))
+
+(unless (have-pubkey-algo? "ECDH")
+       (skip "No ECC support due to an old Libgcrypt"))
+
+(info "Preparing for ECC test")
+(for-each
+ (lambda (grip)
+   (catch '() (unlink (string-append "private-keys-v1.d/" grip ".key")))
+   (call-check `(,(tool 'gpg-preset-passphrase)
+                --preset --passphrase ecc ,grip)))
+ keygrips)
+
+(info "Importing ECC public keys")
+(for-each
+ (lambda (keyid)
+   (call `(,(tool 'gpg) --delete-key --batch --yes ,keyid)))
+ mainkeyids)
+
+(for-each
+ (lambda (n)
+   (call-check `(,(tool 'gpg) --import
+                ,(in-srcdir (string-append
+                             "samplekeys/ecc-sample-"
+                             (number->string n)
+                             "-pub.asc")))))
+ '(1 2 3))
+
+;; The following is an opaque ECDSA signature on a message "This is one
+;; line\n" (17 byte long) by the primary 256 bit key:
+(define msg_opaque_signed_256 "-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2.1.0-ecc (GNU/Linux)
+
+owGbwMvMwCHMvVT3w66lc+cwrlFK4k5N1k3KT6nUK6ko8Zl8MSEkI7NYAYjy81IV
+cjLzUrk64lgYhDkY2FiZQNIMXJwCMO31rxgZ+tW/zesUPxWzdKWrtLGW/LkP5rXL
+V/Yvnr/EKjBbQuvZSYa/klsum6XFmTze+maVgclT6Rc6hzqqxNy6o6qdTTmLJuvp
+AQA=
+=GDv4
+-----END PGP MESSAGE----")
+
+;; The following is an opaque ECDSA signature on a message "This is one
+;; line\n" (17 byte long) by the primary 384 bit key:
+(define msg_opaque_signed_384 "-----BEGIN PGP MESSAGE-----
+Version: PGP Command Line v10.0.0 (Linux)
+
+qANQR1DIqwE7wsvMwCnM2WDcwR9SOJ/xtFISd25qcXFieqpeSUUJAxCEZGQWKwBR
+fl6qQk5mXirXoXJmVgbfYC5xmC5hzsDPjHXqbDLzpXpTBXSZV3L6bAgP3Kq7Ykmo
+7Ds1v4UfBS+3CSSon7Pzq79WLjzXXEH54MkjPxnrw+8cfMVnY7Bi18J702Nnsa7a
+9lMv/PM0/ao9CZ3KX7Q+Tv1rllTZ5Hj4V1frw431QnHfAA==
+=elKT
+-----END PGP MESSAGE-----")
+
+;; The following is an opaque ECDSA signature on a message "This is one
+;; line\n" (17 byte long) by the primary 521 bit key:
+(define msg_opaque_signed_521 "-----BEGIN PGP MESSAGE-----
+Version: PGP Command Line v10.0.0 (Linux)
+
+qANQR1DIwA8BO8LLzMAlnO3Y8tB1vf4/xtNKSdy5qcXFiempeiUVJQxAEJKRWawA
+RPl5qQo5mXmpXIdmMLMy+AaLnoLpEubatpeJY2Lystd7Qt32q2UcvRS5kNPWtDB7
+ryufvcrWtFM7Jx8qXKDxZuqr7b9PGv1Ssk+I8TzB2O9dZC+n/jv+PAdbuu7mLe33
+Gf9pLd3weV3Qno6FOqxGa5ZszQx+uer2xH3/El9x/2pVeO4l15ScsL7qWMTmffmG
+Ic1RdzgeCfosMF+l/zVRchcLKzenEQA=
+=ATtX
+-----END PGP MESSAGE-----")
+
+(lettmp (z)
+  (letfd ((fd (open z (logior O_WRONLY O_CREAT O_BINARY) #o600)))
+        (display "This is one line\n" (fdopen fd "wb")))
+
+  (for-each-p
+   "Checking opaque ECDSA signatures"
+   (lambda (test)
+     (lettmp (x y)
+       (call-with-output-file
+          x (lambda (p) (display (eval test (current-environment)) p)))
+       (call-check `(,(tool 'gpg) --verify ,x))
+       (call-check `(,(tool 'gpg) --output ,y ,x))
+       (unless (file=? y z) (error "mismatch"))))
+   '(msg_opaque_signed_256 msg_opaque_signed_384 msg_opaque_signed_521)))
+
+;;
+;; Import the secret keys so that we now can sign and decrypt.
+;;
+;; Note that the PGP generated secret keys are not self-signed, thus we
+;; need to pass an appropriate option.
+;;
+(info "Importing ECC secret keys")
+(setenv "PINENTRY_USER_DATA" "ecc" #t)
+(for-each
+ (lambda (n)
+   (call-check `(,(tool 'gpg) --import
+                ,@(if (> n 1) '(--allow-non-selfsigned-uid) '())
+                ,(in-srcdir (string-append
+                             "samplekeys/ecc-sample-"
+                             (number->string n)
+                             "-sec.asc")))))
+ '(1 2 3))
+
+;;
+;; Check a few sample encrtpted messages.
+;;
+(info "Checking ECC encryption")
+
+;; The following block encrypts the text "This is one line\n", 17 bytes,
+;; with the subkey 4089AB73.
+(define msg_encrypted_256 "-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2.1.0-ecc (GNU/Linux)
+
+hH4Dd863o0CJq3MSAgMEHdIYZQx+rV1cjy7qitIOEICFFzp4cjsRX4r+rDdMcQUs
+h7VZmbP1c9C0s9sgCKwubWfkcYUl2ZOju4gy+s4MYTBb4/j8JjnJ9Bqn6LWutTXJ
+zwsdP13VIJLnhiNqISdR3/6xWQ0ICRYzwb95nUZ1c1DSVgFpjPgUvi4pgYbTpcDB
+jzILKWBfBDT/jck169XE8vgtbcqVQYZ7lZpaY9CzEbC+4dXZmV1gm5MafpTyFWgH
+VnyrZB4gad9Lp9e0RKHHcOOE7s/NeLuu
+=odUZ
+-----END PGP MESSAGE-----")
+
+;; The following block encrypts the text "This is one line\n", 17 bytes,
+;; with the subkey 9A201946:
+(define msg_encrypted_384 "-----BEGIN PGP MESSAGE-----
+Version: PGP Command Line v10.0.0 (Linux)
+
+qANQR1DBngOqi5OPmiAZRhIDAwQqIr/00cJyf+QP+VA4QKVkk77KMHdz9OVaR2XK
+0VYu0F/HPm89vL2orfm2hrAZxY9G2R0PG4Wk5Lg04UjKca/O72uWtjdPYulFidmo
+uB0QpzXFz22ZZinxeVPLPEr19Pow0EwCc95cg4HAgrD0nV9vRcTJ/+juVfvsJhAO
+isMKqrFNMvwnK5A1ECeyVXe7oLZl0lUBRhLr59QTtvf85QJjg/m5kaGy8XCJvLv3
+61pZa6KUmw89PjtPak7ebcjnINL01vwmyeg1PAyW/xjeGGvcO+R4P1b4ewyFnJyR
+svzIJcP7d4DqYOw7
+=oiTJ
+-----END PGP MESSAGE-----")
+
+;; The following block encrypts the text "This is one line\n", 17 bytes,
+;; with the subkey A81C4838:
+(define msg_encrypted_521 "-----BEGIN PGP MESSAGE-----
+Version: PGP Command Line v10.0.0 (Linux)
+
+qANQR1DBwAIDB+qqSKgcSDgSBCMEAKpzTUxB4c56C7g09ekD9I+ttC5ER/xzDmXU
+OJmFqU5w3FllhFj4TgGxxdH+8fv4W2Ag0IKoJvIY9V1V7oUCClfqAR01QbN7jGH/
+I9GFFnH19AYEgMKgFmh14ZwN1BS6/VHh+H4apaYqapbx8/09EL+DV9zWLX4GRLXQ
+VqCR1N2rXE29MJFzGmDOCueQNkUjcbuenoCSKcNT+6xhO27U9IYVCg4BhRUDGfD6
+dhfRzBLxL+bKR9JVAe46+K8NLjRVu/bd4Iounx4UF5dBk8ERy+/8k9XantDoQgo6
+RPqCad4Dg/QqkpbK3y574ds3VFNJmc4dVpsXm7lGV5w0FBxhVNPoWNhhECMlTroX
+Rg==
+=5GqW
+-----END PGP MESSAGE-----")
+
+(lettmp (z)
+  (letfd ((fd (open z (logior O_WRONLY O_CREAT O_BINARY) #o600)))
+        (display "This is one line\n" (fdopen fd "wb")))
+
+  (for-each-p
+   "Checking ECDSA decryption"
+   (lambda (test)
+     (lettmp (x y)
+       (call-with-output-file
+          x (lambda (p) (display (eval test (current-environment)) p)))
+       (call-check `(,@GPG --yes --output ,y ,x))
+       (unless (file=? y z) (error "mismatch"))))
+   '(msg_encrypted_256 msg_encrypted_384 msg_encrypted_521)))
+
+;;
+;; Now check that we can encrypt and decrypt our own messages.
+;;
+;; Note that we don't need to provide a passppharse because we already
+;; preset the passphrase into the gpg-agent.
+;;
+(for-each-p
+ "Checking ECC encryption and decryption"
+ (lambda (source)
+   (for-each-p
+    ""
+    (lambda (keyid)
+      (tr:do
+       (tr:open source)
+       (tr:gpg "" `(--yes --encrypt --recipient ,keyid))
+       (tr:gpg "" '(--yes))
+       (tr:assert-identity source)))
+    mainkeyids))
+ (append plain-files data-files))
+
+;;
+;; Now check that we can sign and verify our own messages.
+;;
+(for-each-p
+ "Checking ECC signing and verifiction"
+ (lambda (source)
+   (for-each-p
+    ""
+    (lambda (keyid)
+      (tr:do
+       (tr:open source)
+       (tr:gpg "" `(--yes --sign --local-user ,keyid))
+       (tr:gpg "" '(--yes))
+       (tr:assert-identity source)))
+    mainkeyids))
+ (append plain-files data-files))
+
+;;
+;; Let us also try to import the keys only from a secret keyblock.
+;;
+;; Because PGP does not sign the UID, it is not very useful to work
+;; with this key unless we go into the trouble of adding the
+;; self-signature.
+;;
+(info "Importing ECC secret keys directly")
+(for-each
+ (lambda (keyid)
+   (catch '() (unlink (string-append "private-keys-v1.d/" keyid ".key"))))
+ keygrips)
+(for-each
+ (lambda (keyid)
+   (call `(,(tool 'gpg) --delete-key --batch --yes ,keyid)))
+ mainkeyids)
+
+(for-each
+ (lambda (n)
+   (call-check `(,(tool 'gpg) --import
+                ,@(if (> n 1) '(--allow-non-selfsigned-uid) '())
+                ,(in-srcdir (string-append
+                             "samplekeys/ecc-sample-"
+                             (number->string n)
+                             "-sec.asc")))))
+ '(1 2 3))
diff --git a/tests/openpgp/encrypt-dsa.scm b/tests/openpgp/encrypt-dsa.scm
new file mode 100755 (executable)
index 0000000..5228e43
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking encryption using DSA"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg "" `(--yes --encrypt --recipient ,dsa-usrname2))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
+
+(for-each-p
+ "Checking encryption using DSA and a specific cipher algorithm"
+ (lambda (cipher)
+   (for-each-p
+    ""
+    (lambda (source)
+      (tr:do
+       (tr:open source)
+       (tr:gpg "" `(--yes --encrypt --recipient ,dsa-usrname2
+                         --cipher-algo ,cipher))
+       (tr:gpg "" '(--yes))
+       (tr:assert-identity source)))
+    (append plain-files data-files)))
+ all-cipher-algos)
diff --git a/tests/openpgp/encrypt.scm b/tests/openpgp/encrypt.scm
new file mode 100755 (executable)
index 0000000..7452fc5
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking encryption"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg "" `(--yes --encrypt --recipient ,usrname2))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
+
+(for-each-p
+ "Checking encryption using a specific cipher algorithm"
+ (lambda (cipher)
+   (for-each-p
+    ""
+    (lambda (source)
+      (tr:do
+       (tr:open source)
+       (tr:gpg "" `(--yes --encrypt --recipient ,usrname2
+                         --cipher-algo ,cipher))
+       (tr:gpg "" '(--yes))
+       (tr:assert-identity source)))
+    (append plain-files data-files)))
+ all-cipher-algos)
+
+
+;; We encrypt to two keys and we have also put the first key into our
+;; pubring, so that decryption will work.
+(for-each-p
+ "Checking encryption using a key from file"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg "" `(--yes -v --no-keyring --encrypt
+                 --recipient-file ,(in-srcdir key-file1)
+                 --hidden-recipient-file ,(in-srcdir key-file2)))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ plain-files)
diff --git a/tests/openpgp/encryptp.scm b/tests/openpgp/encryptp.scm
new file mode 100755 (executable)
index 0000000..2b010ac
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking encryption and decryption using pipes"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:pipe-do
+     (pipe:gpg `(--yes --encrypt --recipient ,usrname2))
+     (pipe:gpg '(--yes)))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
diff --git a/tests/openpgp/export.scm b/tests/openpgp/export.scm
new file mode 100755 (executable)
index 0000000..8291705
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define (check-for predicate lines message)
+  (unless (any predicate lines)
+         (error message)))
+
+(define (check-exported-key dump keyid)
+  (check-for (lambda (l)
+              (and (string-prefix? l " keyid: ")
+                   (string-suffix? l keyid))) dump
+                   "Keyid not found")
+  (check-for (lambda (l) (string-prefix? l ":user ID packet:")) dump
+            "User ID packet not found")
+  (check-for (lambda (l)
+              (and (string-prefix? l ":signature packet:")
+                   (string-contains? l "keyid")
+                   (string-suffix? l keyid))) dump
+                   "Signature packet not found"))
+
+(define (check-exported-public-key packet-dump keyid)
+  (let ((dump (string-split packet-dump #\newline)))
+    (check-for (lambda (l) (string-prefix? l ":public key packet:")) dump
+              "Public key packet not found")
+    (check-exported-key dump keyid)))
+
+(define (check-exported-private-key packet-dump keyid)
+  (let ((dump (string-split packet-dump #\newline)))
+    (check-for (lambda (l) (string-prefix? l ":secret key packet:")) dump
+              "Secret key packet not found")
+    (check-exported-key dump keyid)))
+
+(lettmp
+ ;; Prepare two temporary files for communication with the fake
+ ;; pinentry program.
+ (logfile ppfile)
+
+ (define (prepare-passphrases . passphrases)
+   (call-with-output-file ppfile
+     (lambda (port)
+       (for-each (lambda (passphrase)
+                  (display passphrase port)
+                  (display #\newline port)) passphrases))))
+
+ (define CONFIRM "fake-entry being started to CONFIRM the weak phrase")
+
+ (define (assert-passphrases-consumed)
+   (call-with-input-file ppfile
+     (lambda (port)
+       (unless
+       (eof-object? (peek-char port))
+       (error (string-append
+               "Expected all passphrases to be consumed, but found: "
+               (read-all port)))))))
+
+ (setenv "PINENTRY_USER_DATA"
+        (string-append "--logfile=" logfile " --passphrasefile=" ppfile) #t)
+
+ (for-each-p
+  "Checking key export"
+  (lambda (keyid)
+    (tr:do
+     (tr:pipe-do
+      (pipe:gpg `(--export ,keyid))
+      (pipe:gpg '(--list-packets)))
+     (tr:call-with-content check-exported-public-key keyid))
+
+    (if (string=? "D74C5F22" keyid)
+       ;; Key D74C5F22 is protected by a passphrase.  Prepare this
+       ;; one.  Currently, GnuPG does not ask for an export passphrase
+       ;; in this case.
+       (prepare-passphrases usrpass1))
+
+    (tr:do
+     (tr:pipe-do
+      (pipe:gpg `(--export-secret-keys ,keyid))
+      (pipe:gpg '(--list-packets)))
+     (tr:call-with-content check-exported-private-key keyid))
+
+    (assert-passphrases-consumed))
+  '("D74C5F22" "C40FDECF" "ECABF51D")))
diff --git a/tests/openpgp/finish.scm b/tests/openpgp/finish.scm
new file mode 100755 (executable)
index 0000000..48801c8
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(echo "Killing gpg-agent...")
+(call-check `(,(tool 'gpg-connect-agent) --verbose killagent /bye))
diff --git a/tests/openpgp/genkey1024.scm b/tests/openpgp/genkey1024.scm
new file mode 100755 (executable)
index 0000000..9870f46
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define (genkey config)
+  (pipe:do
+   (pipe:echo config)
+   (pipe:spawn `(,(tool 'gpg) --quiet --batch --gen-key))))
+
+(info "Checking batch key generation")
+(genkey "Key-Type: DSA
+Key-Length: 1024
+Subkey-Type: ELG
+Subkey-Length: 1024
+Name-Real: Harry H.
+Name-Comment: test key
+Name-Email: hh@@ddorf.de
+Expire-Date: 1
+%no-protection
+%transient-key
+%commit
+")
+
+(if (have-pubkey-algo? "RSA")
+    (genkey "Key-Type: RSA
+Key-Length: 1024
+Key-Usage: sign,encrypt
+Name-Real: Harry A.
+Name-Comment: RSA test key
+Name-Email: hh@@ddorf.de
+Expire-Date: 2
+%no-protection
+%transient-key
+%commit
+"))
diff --git a/tests/openpgp/gpgtar.scm b/tests/openpgp/gpgtar.scm
new file mode 100755 (executable)
index 0000000..07f2fd7
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(unless (= 0 (call `(,(tool 'gpgtar) --help)))
+       (skip "gpgtar not installed"))
+
+(define testfiles (append plain-files data-files))
+(define gpgargs
+  (if have-opt-always-trust
+      "--no-permission-warning --always-trust"
+      "--no-permission-warning"))
+
+(define (do-test create-flags inspect-flags extract-flags)
+  (lettmp (archive)
+    (call-check `(,(tool 'gpgtar) --gpg ,(tool 'gpg) --gpg-args ,gpgargs
+                 ,@create-flags
+                 --output ,archive
+                 ,@testfiles))
+    (tr:do
+     (tr:pipe-do
+      (pipe:spawn `(,(tool 'gpgtar) --gpg ,(tool 'gpg) --gpg-args ,gpgargs
+                   --list-archive ,@inspect-flags
+                   ,archive)))
+     (tr:call-with-content
+      (lambda (c)
+       (unless (all (lambda (f) (string-contains? c f)) testfiles)
+               (error "some file(s) are missing from archive")))))
+
+    (with-temporary-working-directory
+     (call-check `(,(tool 'gpgtar) --gpg ,(tool 'gpg) --gpg-args ,gpgargs
+                  --tar-args --directory=.
+                  ,@extract-flags
+                  ,archive))
+
+     (for-each
+      (lambda (f) (unless (call-with-input-file f (lambda (x) #t))
+                         (error (string-append "missing file: " f))))
+      testfiles))))
+
+(info "Checking gpgtar without encryption")
+(do-test '(--skip-crypto --encrypt) '(--skip-crypto)
+        '(--skip-crypto --decrypt))
+
+(info "Checking gpgtar without encryption with nicer actions")
+(do-test '(--create) '(--skip-crypto) '(--extract))
+
+(info "Checking gpgtar with asymmetric encryption")
+(do-test `(--encrypt --recipient ,usrname2) '() '(--decrypt))
+
+(info "Checking gpgtar with asymmetric encryption and signature")
+(do-test `(--encrypt --recipient ,usrname2 --sign --local-user ,usrname3)
+        '() '(--decrypt))
+
+(info "Checking gpgtar with signature")
+(do-test `(--sign --local-user ,usrname3) '() '(--decrypt))
+
+(lettmp (passphrasefile)
+  (letfd ((fd (open passphrasefile (logior O_WRONLY O_CREAT O_BINARY) #o600)))
+    (display "streng geheimes hupsipupsi" (fdopen fd "wb")))
+
+  (let ((ppflags `(--gpg-args ,(string-append "--passphrase-file="
+                                             passphrasefile))))
+    (info "Checking gpgtar with symmetric encryption")
+    (do-test `(,@ppflags --symmetric) ppflags (cons '--decrypt ppflags))
+
+    (info "Checking gpgtar with symmetric encryption and chosen cipher")
+    (do-test `(,@ppflags --symmetric --gpg-args
+                        ,(string-append "--cipher=" (car all-cipher-algos)))
+            ppflags (cons '--decrypt ppflags))
+
+    (info "Checking gpgtar with both symmetric and asymmetric encryption")
+    (do-test `(,@ppflags --symmetric --encrypt --recipient ,usrname2
+                        --sign --local-user ,usrname3)
+            ppflags (cons '--decrypt ppflags))))
diff --git a/tests/openpgp/import.scm b/tests/openpgp/import.scm
new file mode 100755 (executable)
index 0000000..580acea
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(info "Checking bug 894: segv importing certain keys.")
+(call-check `(,(tool 'gpg) --import ,(in-srcdir "bug894-test.asc")))
+
+(define keyid "0xC108E83A")
+(info "Checking bug 1223: designated revoker sigs are not properly merged.")
+(call `(,(tool 'gpg) --delete-key --batch --yes ,keyid))
+(call `(,(tool 'gpg) --import ,(in-srcdir "bug1223-bogus.asc")))
+(call `(,(tool 'gpg) --import ,(in-srcdir "bug1223-good.asc")))
+(tr:do
+ (tr:pipe-do
+  (pipe:gpg `(--list-keys --with-colons ,keyid)))
+ (tr:call-with-content
+  (lambda (c)
+    ;; XXX we do not have a regexp library
+    (unless (any (lambda (line)
+                  (and (string-prefix? line "rvk:")
+                       (string-contains? line ":0EE5BE979282D80B9F7540F1CCD2ED94D21739E9:")))
+                (string-split c #\newline))
+           (exit 1)))))
+
+(define fpr1 "9E669861368BCA0BE42DAF7DDDA252EBB8EBE1AF")
+(define fpr2 "A55120427374F3F7AA5F1166DDA252EBB8EBE1AF")
+(info "Checking import of two keys with colliding long key ids.")
+(call `(,(tool 'gpg) --delete-key --batch --yes ,fpr1 ,fpr2))
+(call `(,(tool 'gpg) --import ,(in-srcdir "samplekeys/dda252ebb8ebe1af-1.asc")))
+(call `(,(tool 'gpg) --import ,(in-srcdir "samplekeys/dda252ebb8ebe1af-2.asc")))
+(tr:do
+ (tr:pipe-do
+  (pipe:gpg `(--list-keys --with-colons ,fpr1 ,fpr2)))
+ (tr:call-with-content
+  (lambda (c)
+    ;; XXX we do not have a regexp library
+    (let ((keys (filter
+                (lambda (line)
+                  (and (string-prefix? line "pub:")
+                       (string-contains? line ":4096:1:DDA252EBB8EBE1AF:")))
+                (string-split c #\newline))))
+      (unless (= 2 (length keys))
+             (error "Importing keys with long id collision failed"))))))
diff --git a/tests/openpgp/mds.scm b/tests/openpgp/mds.scm
new file mode 100755 (executable)
index 0000000..8ca6c7b
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(define empty-string-hashes
+  `((1 "D41D8CD98F00B204E9800998ECF8427E" "MD5")
+    (2 "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709" "SHA1")
+    (3 "9C1185A5C5E9FC54612808977EE8F548B2258D31" "RIPEMD160")
+    (11 "D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F" "SHA224")
+    (8 "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" "SHA256")
+    (9 "38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898B95B" "SHA384")
+    (10
+     "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E"
+     "SHA512")))
+
+(define abc-hashes
+  `((1 "C3FCD3D76192E4007DFB496CCA67E13B" "MD5")
+    (2 "32D10C7B8CF96570CA04CE37F2A19D84240D3A89" "SHA1")
+    (3 "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC" "RIPEMD160")
+    (11 "45A5F72C39C5CFF2522EB3429799E49E5F44B356EF926BCF390DCCC2" "SHA224")
+    (8 "71C480DF93D6AE2F1EFAD1447C66C9525E316218CF51FC8D9ED832F2DAF18B73" "SHA256")
+    (9 "FEB67349DF3DB6F5924815D6C3DC133F091809213731FE5C7B5F4999E463479FF2877F5F2936FA63BB43784B12F3EBB4" "SHA384")
+    (10 "4DBFF86CC2CA1BAE1E16468A05CB9881C97F1753BCE3619034898FAA1AABE429955A1BF8EC483D7421FE3C1646613A59ED5441FB0F321389F77F48A879C7B1F1" "SHA512")))
+
+;; Symbolic names for the triples above.
+(define :algo car)
+(define :value cadr)
+(define :name caddr)
+
+;; Test whether HASH matches REF.
+(define (test-hash hash ref)
+  (unless (eq? #f ref)
+         (if (not (string=? (:value hash) (:value ref)))
+           (error "failed"))))
+
+;; Test whether the hashes computed over S match the REFERENCE set.
+(define (test-hashes msg s reference)
+  (for-each-p'
+   msg
+   (lambda (hash) (test-hash hash (assv (:algo hash) reference)))
+   (lambda (hash)
+     (let ((ref (assv (:algo hash) reference)))
+       (if (eq? #f ref)
+          (string-append "no-ref-for:" (number->string (:algo hash)))
+          (:name ref))))
+   (gpg-hash-string '(--print-mds) s)))
+
+(test-hashes "Hashing the empty string"
+ "" empty-string-hashes)
+(test-hashes "Hashing the string \"abcdefghijklmnopqrstuvwxyz\""
+ "abcdefghijklmnopqrstuvwxyz" abc-hashes)
diff --git a/tests/openpgp/multisig.scm b/tests/openpgp/multisig.scm
new file mode 100755 (executable)
index 0000000..53c905f
--- /dev/null
@@ -0,0 +1,168 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+;; Check that gpg verifies only signatures where there is no ambiguity
+;; in the order of packets.  Needs the Demo Keys Lima and Mike.
+;;
+;; Note: We do not support multiple signatures anymore thus this test is
+;; not really needed because verify could do the same.  We keep it anyway.
+
+(load (with-path "defs.scm"))
+
+(define sig-1ls1ls-valid "
+-----BEGIN PGP ARMORED FILE-----
+
+kA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogq9EkgYW0gc29ycnksIEkgY2FuJ3Qg
+ZG8gdGhhdAqIPwMFADqIKvQ3yrUft5ED+BEC2joAoJaSaXOZEtSZqQ780HIXG77e
+8PB7AJ4wCprmaFTO0fBaTcXDuEOBdAWnOZANAwACETfKtR+3kQP4AawnYgV0ZXh0
+MTqIKvRJIGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRoYXQKiD8DBQA6iCr0N8q1H7eR
+A/gRAto6AKCWkmlzmRLUmakO/NByFxu+3vDwewCeMAqa5mhUztHwWk3Fw7hDgXQF
+pzk=
+=8jSC
+-----END PGP ARMORED FILE-----
+")
+(define sig-ls-valid "
+-----BEGIN PGP ARMORED FILE-----
+
+rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI
+K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT
+QDUFTH2PvZRxjw==
+=J+lb
+-----END PGP ARMORED FILE-----
+")
+(define sig-sl-valid "
+-----BEGIN PGP ARMORED FILE-----
+
+iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU
+tH60PslLE0A1BUx9j72UcY+sJ2IFdGV4dDE6iCtLSSBhbSBzb3JyeSwgSSBjYW4n
+dCBkbyB0aGF0Cg==
+=N9MP
+-----END PGP ARMORED FILE-----
+")
+(define sig-11lss-valid-but-is-not "
+-----BEGIN PGP ARMORED FILE-----
+
+kA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogyXUkgYW0g
+c29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED+BECwQAAnRXT
+mXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp5Yg/AwUAOogy
+XTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0P01WmbgZJoZB
+Q341WRXKS/at
+=Ekrs
+-----END PGP ARMORED FILE-----
+")
+(define sig-11lss11lss-valid-but-is-not "
+-----BEGIN PGP ARMORED FILE-----
+
+kA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogyXUkgYW0g
+c29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED+BECwQAAnRXT
+mXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp5Yg/AwUAOogy
+XTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0P01WmbgZJoZB
+Q341WRXKS/atkA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQx
+OogyXUkgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED
++BECwQAAnRXTmXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp
+5Yg/AwUAOogyXTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0
+P01WmbgZJoZBQ341WRXKS/at
+=P1Mu
+-----END PGP ARMORED FILE-----
+")
+(define sig-ssl-valid-but-is-not "
+-----BEGIN PGP ARMORED FILE-----
+
+iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU
+tH60PslLE0A1BUx9j72UcY+IPwMFADqIK0s3yrUft5ED+BECLQMAn2jZUNOpB4Ou
+urSQkc2TRfg6ek02AJ9+oJS0frQ+yUsTQDUFTH2PvZRxj6wnYgV0ZXh0MTqIK0tJ
+IGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRoYXQK
+=Zven
+-----END PGP ARMORED FILE-----
+")
+(define sig-1lsls-invalid "
+-----BEGIN PGP ARMORED FILE-----
+
+kA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogq9EkgYW0gc29ycnksIEkgY2FuJ3Qg
+ZG8gdGhhdAqIPwMFADqIKvQ3yrUft5ED+BEC2joAoJaSaXOZEtSZqQ780HIXG77e
+8PB7AJ4wCprmaFTO0fBaTcXDuEOBdAWnOawnYgV0ZXh0MTqIK0tJIGFtIHNvcnJ5
+LCBJIGNhbid0IGRvIHRoYXQKiD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeD
+rrq0kJHNk0X4OnpNNgCffqCUtH60PslLE0A1BUx9j72UcY8=
+=nkeu
+-----END PGP ARMORED FILE-----
+")
+(define sig-lsls-invalid "
+-----BEGIN PGP ARMORED FILE-----
+
+rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI
+K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT
+QDUFTH2PvZRxj6wnYgV0ZXh0MTqIK0tJIGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRo
+YXQKiD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCf
+fqCUtH60PslLE0A1BUx9j72UcY8=
+=BlZH
+-----END PGP ARMORED FILE-----
+")
+(define sig-lss-invalid "
+-----BEGIN PGP ARMORED FILE-----
+
+rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI
+K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT
+QDUFTH2PvZRxj4g/AwUAOogrSzfKtR+3kQP4EQItAwCfaNlQ06kHg666tJCRzZNF
++Dp6TTYAn36glLR+tD7JSxNANQVMfY+9lHGP
+=jmt6
+-----END PGP ARMORED FILE-----
+")
+(define sig-slsl-invalid "
+-----BEGIN PGP ARMORED FILE-----
+
+iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU
+tH60PslLE0A1BUx9j72UcY+sJ2IFdGV4dDE6iCtLSSBhbSBzb3JyeSwgSSBjYW4n
+dCBkbyB0aGF0Cog/AwUAOogrSzfKtR+3kQP4EQItAwCfaNlQ06kHg666tJCRzZNF
++Dp6TTYAn36glLR+tD7JSxNANQVMfY+9lHGPrCdiBXRleHQxOogrS0kgYW0gc29y
+cnksIEkgY2FuJ3QgZG8gdGhhdAo=
+=phBF
+-----END PGP ARMORED FILE-----
+")
+
+(for-each-p
+ "Checking that a valid signature is verified as such"
+ (lambda (armored-file)
+   (tr:do
+    (tr:pipe-do
+     (pipe:echo (eval armored-file (current-environment)))
+     (pipe:spawn `(,@GPG --dearmor)))
+    (tr:spawn "" `(,@GPG --verify **in**))))
+ '(sig-sl-valid))
+
+;; ???
+;;
+;; #for i in "$sig-11lss-valid-but-is-not" "$sig-11lss11lss-valid-but-is-not" \
+;; #         "$sig-ssl-valid-but-is-not"; do
+;; #    echo "$i" | $GPG --dearmor >x
+;; #    $GPG --verify <x 2>/dev/null || error "valid is invalid"
+;; #done
+
+(for-each-p
+ "Checking that an invalid signature is verified as such"
+ (lambda (armored-file)
+   (lettmp (file)
+     (pipe:do
+      (pipe:echo (eval armored-file (current-environment)))
+      (pipe:spawn `(,@GPG --dearmor))
+      (pipe:write-to file (logior O_WRONLY O_CREAT O_BINARY) #o600))
+
+     (if (= 0 (call `(,@GPG --verify ,file)))
+        (error "Bad signature verified ok")))
+ '(sig-1ls1ls-valid sig-ls-valid sig-1lsls-invalid
+                   sig-lsls-invalid sig-lss-invalid sig-slsl-invalid))
diff --git a/tests/openpgp/privkeys/1E28F20E41B54C2D1234D896096495FF57E08D18.asc b/tests/openpgp/privkeys/1E28F20E41B54C2D1234D896096495FF57E08D18.asc
new file mode 100644 (file)
index 0000000..d0b621a
--- /dev/null
@@ -0,0 +1,9 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6ZWNjKDU6Y3VydmU3OkVkMjU1MTkpKDU6ZmxhZ3M1
+OmVkZHNhKSgxOnEzMzpAZ8zkuQDL9x7rcvvoo6s3iEF1j88Dknd9nZhLnTEoBRkp
+KDE6ZDMyOnicJkwzhZjYg5Fd8zqmEsZLPdGwe+z+8DU6lq6zj5HcKSkp
+=ZStX
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/privkeys/C6A6390E9388CDBAD71EAEA698233FE5E04F001E.asc b/tests/openpgp/privkeys/C6A6390E9388CDBAD71EAEA698233FE5E04F001E.asc
new file mode 100644 (file)
index 0000000..939e8ab
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6cnNhKDE6bjI1NzoAqBvNbHXRfWWcek7De5Xpw8bO
+d8KibdW2sE6F2ZeqifoTvLTDcv2lIGqqovKQuRV9x5UkUIY0RQ0F6uI0d/o3nBSt
+8H8JsUylzCoTeds4UiFgpRA+O+egd8DyE7sABtlmBXHApYa7Vl/I/sASuSKS1VQF
+0JzkWSzj+381GZDtSg7t2z+A+n9S0MmrSM4EtPHZ5aelr7CQ65FHhmOkebJqcfX/
+j6gVX1FaZnJGzDkfgWDybaZWU9JXs+KlrJnVm6lO2YXb54TBnE2wW5PVm30dSCab
+YoHrivL01NuCadhUI+oiAVfTg41H69dRCelt07x2lrnXXdIX1/Q58h/a4IawxSko
+MTplMzoBAAEpKDE6ZDI1Njog6qS8HovBCoLrvf1v9wg5YfWupIlKiWTGu/FgjF6D
+uthfhGOa4giRwuEbm/RzkT46NL1SGR0mAilM9zL/5Ro7cR8n7rAWq+PxCLIck6zB
+BDEY0QfmkfGtUTX1YBHexXXBDieDIdEP1hyUqUZhQuBObi/fS8E4pt4TMjLTCTo1
+XEqZxqvK11AD6y2GddnCtH8vTgUaALzxNks23nngDEAdaDfJMHobST4Jb9RYVHNN
+zsZnLkKRr+GIemOoRXlCvTmTaw+8Vh6vUq8OWB5jryNxmt64FtWAHpLcW0n5OE6S
+6OlndqM92Xe9NT12wu75Mn+qTYrVauSPQvVveZMakG/hKSgxOnAxMjk6AMNAbeJx
+Bb6BlIWYMYrpAhkuPBgB3HvS0wZQ/n0j8LLEh+BJI8xa9HgDz7LOJPo00w6ERHvb
+Q+8VVBP69wxwHFJSfxJsImqUmQYXgoA2n/6GAqfj4oFK/FAsFd350bkaFnZcSxqj
+hJai8JQPku0cZqPudfRzThX5XIBbynMBNqIxKSgxOnExMjk6ANxpdW6WqMrWGerg
+X1i4MQd9ofyyWaT2XaGrnwMJY1qUqAqPViqZWPpPmya8mVrT9XkajdtPUm0zVzeK
+IjEScdvoS/pwkIMmM2+GRCFCo9zrsExeqa1cQpc8GFDZgynZ9/jXWeRiidU1xTMt
+gANAiZWOb8Ww6ti9p+t96liUEB7VKSgxOnUxMjk6AK/BZIZC/C6GJyRhEoTBlzmn
+nSC5eC6MojPTOQwd5VIkeEq4illBE7DF/5gFw/fufn7s+0vicZx/8yLH1mFYkbwq
+DfuoY/Da5lnRFw6fGOj4N0ikS26FApjlh2DS09HtIFuNAhErr5PDPjF1F31XL/1M
+50jkxfKPamxMiEs8it0VKSkp
+=GHvX
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/privkeys/D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3.asc b/tests/openpgp/privkeys/D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3.asc
new file mode 100644 (file)
index 0000000..86f6acf
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6cnNhKDE6bjI1NzoA255CUJxFEKLVwEoSgwZqXd94
+AhjGUbMY6NXdFj5cCq0JmWZrbpT/5OblTrymiH1iLmI0ymo+/s8vh6NtB98dhr1s
+yH3asNQfXZRfF+u5X5hLDNPF4sUelsl4+EUef0Hbc9U+e+8F8A9TMxELSqQ8Ul3H
+u42hc+/ugkc1G/8++Sv/f60TqWcUR2GmuiAvkuS1WmdATMhwPr7vMfssV0X0mboz
+32//b/UfuOyctso5FM+bRaKrEJDQ2WDg57yqnaqsKEgajW0jElpAVIn792W6YWKO
+k4auYSpO5f7BVs40Z+bxKGxiH87z9fnmlYAsQwPOOxZwWaCSrReeheK6c6emASko
+MTplMzoBAAEpKDE6ZDI1NjoYgHaQ5xkEJcvyhmZm/H8/doq9XnrkazZ7O5OimKsi
+Jx4BYZ4uGdeBd9/bbKFTwaauMBddrIQstNFuW5BIJt9KGgtvRC3y49JABClRJ45o
+mOVpSp3dkp+6s5hDHUsCvZvjN3D02LzxLx8u0lb6fopFp4rSD5dqB48KNTGQAbvK
+hqYZ521wmTfYLiy9taVAhqZLHlhfmrHYmdvvKjdNE3tSActlHWXdu119rdHhJ0zJ
+Rxx/N845rl+PXXdFHveQxCBhHBQpSUaKpte+ZbT4vrjyNugD6XjDi4HLI9CysUDP
+A0IFD+BJWw7NgYY51yamT7nNcMD6bJdgtt1FXbSgh7jVKSgxOnAxMjk6AN7btgbl
+HEHrKf77a9ptklDvd2bEkUOwj3bFavB1lpkliW1USoWMx97zjxRPzQOs6EoE7u9Z
+JRDO8xA9ZbI0WOk7io5OHpVp1BHyeqebqfxHzN5wsRphu+peg7vYfENVf0lA8LIU
+NeUkbfEWDQ+inXxqkgD51gPfrU3PRdCDM8fnKSgxOnExMjk6APxHMsTrjaUoITcI
+LqT35wDinFnX1+OgKD00krcUmc+G0ylLMolVxsB4yDVIkY8QfhbaGtFoP45PCnxS
+rvHKrTt/6sZJCWXf+3KaN0QSxyfi/mEPj3KbXhmaY6x8R4aB/M7ipLXNdj/308pu
+a50YPwIYyX0L0qoRBBo/xQDgOsXXKSgxOnUxMjk6AMzWw92nzShDRzPZwBvb48YY
+YzZFiFtJbcZ1n8DaiM7VmzAkRqwmCu6HPP/8IC4d6UkFUUlHyDyxSaKuA45Y+FR1
+Pb2/Y/mQVsBanK4i+1oL4fYGexFO0qjA+8l2+6BEWbKQX60nIcFXD2hAP0aqWDGO
+lXrPhpWPRrwDd4j9DEvfKSkp
+=1cwG
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/privkeys/EB33B687EB8581AB64D04852A54453E85F3DF62D.asc b/tests/openpgp/privkeys/EB33B687EB8581AB64D04852A54453E85F3DF62D.asc
new file mode 100644 (file)
index 0000000..ede9a91
--- /dev/null
@@ -0,0 +1,10 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6ZWNjKDU6Y3VydmUxMDpDdXJ2ZTI1NTE5KSg1OmZs
+YWdzOTpkamItdHdlYWspKDE6cTMzOkAWeeZlz31O4qTmIKr3CZhlRUXZFxc3YKyo
+CXyIZBBRaykoMTpkMzI6VN/VGmlcwGBPcLTya2hfU4t37nMcFCKdNSXjJ5DFA0Ap
+KSk=
+=eVhB
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/quick-key-manipulation.test b/tests/openpgp/quick-key-manipulation.test
new file mode 100755 (executable)
index 0000000..4185601
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/sh
+# Copyright 2016 Free Software Foundation, Inc.
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.  This file is
+# distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY, to the extent permitted by law; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+. $srcdir/defs.inc || exit 3
+
+export PINENTRY_USER_DATA=test
+
+alpha="Alpha <alpha@example.net>"
+bravo="Bravo <bravo@example.net>"
+
+$GPG --with-colons --with-fingerprint --list-secret-keys ="$alpha" &&
+    error "User ID '$alpha'exists when it should not!"
+$GPG --with-colons --with-fingerprint --list-secret-keys ="$bravo" &&
+    error "User ID '$bravo' exists when it should not!"
+
+#info verify that key creation works
+$GPG --quick-gen-key "$alpha"  || \
+        error "failed to generate key"
+
+fpr=$($GPG --with-colons --with-fingerprint --list-secret-keys ="$alpha" | \
+             grep '^fpr:' | cut -f10 -d: | head -n1)
+
+$GPG --check-trustdb
+
+cleanup() {
+    $GPG --batch --yes --delete-secret-key "0x$fpr"
+    $GPG --batch --yes --delete-key "0x$fpr"
+}
+
+count_uids_of_secret() {
+    if ! [ $($GPG --with-colons --list-secret-keys ="$1" | \
+                    grep -c '^uid:u:') = "$2" ] ; then
+        cleanup
+        error "wrong number of user IDs for '$1' after $3"
+    fi
+}
+
+count_uids_of_secret "$alpha" 1 "key generation"
+
+#info verify that we can add a user ID
+if ! $GPG --quick-adduid ="$alpha" "$bravo" ; then
+    cleanup
+    error "failed to add user id"
+fi
+
+$GPG --check-trustdb
+
+count_uids_of_secret "$alpha" 2 "adding User ID"
+count_uids_of_secret "$bravo" 2 "adding User ID"
+
+#info verify that we can revoke a user ID
+if ! $GPG --quick-revuid ="$bravo" "$alpha"; then
+    cleanup
+    error "failed to revoke user id"
+fi
+
+$GPG --check-trustdb
+
+count_uids_of_secret "$bravo" 1 "revoking user ID"
+
+cleanup
+
+! $GPG --with-colons --list-secret-keys ="$bravo" ||
+    error "key still exists when it should not!"
diff --git a/tests/openpgp/run-tests.scm b/tests/openpgp/run-tests.scm
new file mode 100644 (file)
index 0000000..a921fdb
--- /dev/null
@@ -0,0 +1,209 @@
+;; Test-suite runner.
+;;
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(if (string=? "" (getenv "srcdir"))
+    (begin
+      (echo "Environment variable 'srcdir' not set.  Please point it to"
+           "tests/openpgp.")
+      (exit 2)))
+
+;; Set objdir so that the tests can locate built programs.
+(setenv "objdir" (getcwd) #f)
+
+(define test-pool
+  (package
+   (define (new procs)
+     (package
+      (define (add test)
+       (new (cons test procs)))
+      (define (wait)
+       (let ((unfinished (filter (lambda (t) (not t::retcode)) procs)))
+         (if (null? unfinished)
+             (package)
+             (let* ((commands (map (lambda (t) t::command) unfinished))
+                    (pids (map (lambda (t) t::pid) unfinished))
+                    (results
+                     (map (lambda (pid retcode) (list pid retcode))
+                          pids
+                          (wait-processes (map stringify commands) pids #t))))
+               (new
+                (map (lambda (t)
+                       (if t::retcode
+                           t
+                           (t::set-retcode (cadr (assoc t::pid results)))))
+                     procs))))))
+      (define (passed)
+       (filter (lambda (p) (= 0 p::retcode)) procs))
+      (define (skipped)
+       (filter (lambda (p) (= 77 p::retcode)) procs))
+      (define (hard-errored)
+       (filter (lambda (p) (= 99 p::retcode)) procs))
+      (define (failed)
+       (filter (lambda (p)
+                 (not (or (= 0 p::retcode) (= 77 p::retcode)
+                          (= 99 p::retcode))))
+               procs))
+      (define (report)
+       (echo (length procs) "tests run,"
+             (length (passed)) "succeeded,"
+             (length (failed)) "failed,"
+             (length (skipped)) "skipped.")
+       (length (failed)))))))
+
+(define (verbosity n)
+  (if (= 0 n) '() (cons '--verbose (verbosity (- n 1)))))
+
+(define test
+  (package
+   (define (scm name . args)
+     (new name #f `(,*argv0* ,@(verbosity *verbose*) ,@args
+                            ,(in-srcdir name)) #f #f))
+   (define (new name directory command pid retcode)
+     (package
+      (define (set-directory x)
+       (new name x command pid retcode))
+      (define (set-retcode x)
+       (new name directory command pid x))
+      (define (set-pid x)
+       (new name directory command x retcode))
+      (define (run-sync)
+       (with-working-directory directory
+         (let* ((p (inbound-pipe))
+                (pid (spawn-process-fd command CLOSED_FD
+                                       (:write-end p) (:write-end p))))
+           (close (:write-end p))
+           (splice (:read-end p) STDERR_FILENO)
+           (close (:read-end p))
+           (let ((t' (set-retcode (wait-process name pid #t))))
+             (t'::report)
+             t'))))
+      (define (run-sync-quiet)
+       (with-working-directory directory
+         (set-retcode
+          (wait-process
+           name (spawn-process-fd command CLOSED_FD CLOSED_FD CLOSED_FD) #t))))
+      (define (run-async)
+       (with-working-directory directory
+         (set-pid (spawn-process-fd command CLOSED_FD CLOSED_FD CLOSED_FD))))
+      (define (status)
+       (let ((t (assoc retcode '((0 "PASS") (77 "SKIP") (99 "ERROR")))))
+         (if (not t) "FAIL" (cadr t))))
+      (define (report)
+       (echo (string-append (status retcode) ":") name))))))
+
+(define (run-tests-parallel-shared setup teardown . tests)
+  (setup::run-sync)
+  (let loop ((pool (test-pool::new '())) (tests' tests))
+    (if (null? tests')
+       (let ((results (pool::wait)))
+         (for-each (lambda (t) (t::report)) results::procs)
+         (teardown::run-sync)
+         (exit (results::report)))
+       (let ((test (car tests')))
+         (loop (pool::add (test::run-async)) (cdr tests'))))))
+
+(define (run-tests-parallel-isolated setup teardown . tests)
+  (let loop ((pool (test-pool::new '())) (tests' tests))
+    (if (null? tests')
+       (let ((results (pool::wait)))
+         (for-each (lambda (t)
+                     (let ((teardown' (teardown::set-directory t::directory)))
+                       (teardown'::run-sync-quiet))
+                     (unlink-recursively t::directory)
+                     (t::report)) results::procs)
+         (exit (results::report)))
+       (let* ((wd (mkdtemp "gpgscm-XXXXXX"))
+              (test (car tests'))
+              (test' (test::set-directory wd))
+              (setup' (setup::set-directory wd)))
+         (setup'::run-sync-quiet)
+         (loop (pool::add (test'::run-async)) (cdr tests'))))))
+
+(define (run-tests-sequential-shared setup teardown . tests)
+  (let loop ((pool (test-pool::new '()))
+            (tests' `(,setup ,@tests ,teardown)))
+    (if (null? tests')
+       (let ((results (pool::wait)))
+         (exit (results::report)))
+       (let ((test (car tests')))
+         (loop (pool::add (test::run-sync)) (cdr tests'))))))
+
+(define (run-tests-sequential-isolated setup teardown . tests)
+  (let loop ((pool (test-pool::new '())) (tests' tests))
+    (if (null? tests')
+       (let ((results (pool::wait)))
+         (for-each (lambda (t)
+                     (let ((teardown' (teardown::set-directory t::directory)))
+                       (teardown'::run-sync-quiet))
+                     (unlink-recursively t::directory))
+                   results::procs)
+         (exit (results::report)))
+       (let* ((wd (mkdtemp "gpgscm-XXXXXX"))
+              (test (car tests'))
+              (test' (test::set-directory wd))
+              (setup' (setup::set-directory wd)))
+         (setup'::run-sync-quiet)
+         (loop (pool::add (test'::run-sync)) (cdr tests'))))))
+
+(define all-tests
+  '("version.scm"
+    "mds.scm"
+    "decrypt.scm"
+    "decrypt-dsa.scm"
+    "sigs.scm"
+    "sigs-dsa.scm"
+    "encrypt.scm"
+    "encrypt-dsa.scm"
+    "seat.scm"
+    "clearsig.scm"
+    "encryptp.scm"
+    "detach.scm"
+    "detachm.scm"
+    "armsigs.scm"
+    "armencrypt.scm"
+    "armencryptp.scm"
+    "signencrypt.scm"
+    "signencrypt-dsa.scm"
+    "armsignencrypt.scm"
+    "armdetach.scm"
+    "armdetachm.scm"
+    "genkey1024.scm"
+    "conventional.scm"
+    "conventional-mdc.scm"
+    "multisig.scm"
+    "verify.scm"
+    "armor.scm"
+    "import.scm"
+    "ecc.scm"
+    "4gb-packet.scm"
+    "gpgtar.scm"
+    "use-exact-key.scm"
+    "default-key.scm"))
+
+(let* ((runner (if (member "--parallel" *args*)
+                 (if (member "--shared" *args*)
+                     run-tests-parallel-shared
+                     run-tests-parallel-isolated)
+                 (if (member "--shared" *args*)
+                     run-tests-sequential-shared
+                     run-tests-sequential-isolated)))
+       (tests' (filter (lambda (arg) (not (string-prefix? arg "--"))) *args*))
+       (tests (if (null? tests') all-tests tests')))
+  (apply runner (append (list (test::scm "setup.scm") (test::scm "finish.scm"))
+                       (map test::scm tests))))
index 20d9f51..29524d5 100644 (file)
@@ -14,3 +14,6 @@ whats-new-in-2.1.asc   Collection of sample keys.
 e2e-p256-1-clr.asc     Google End-end-End test key (no protection)
 e2e-p256-1-prt.asc     Ditto, but protected with passphrase "a".
 E657FB607BB4F21C90BB6651BC067AF28BC90111.asc Key with subkeys (no protection)
+rsa-rsa-sample-1.asc   RSA+RSA sample key (no passphrase)
+ed25519-cv25519-sample-1.asc  Ed25519+CV25519 sample key (no passphrase)
+silent-running.asc     Collection of sample secret keys (no passphrases)
diff --git a/tests/openpgp/samplekeys/ed25519-cv25519-sample-1.asc b/tests/openpgp/samplekeys/ed25519-cv25519-sample-1.asc
new file mode 100644 (file)
index 0000000..54d2044
--- /dev/null
@@ -0,0 +1,21 @@
+pub   ed25519 2016-06-22 [SC]
+      B21DEAB4F875FB3DA42F1D1D139563682A020D0A
+      Keygrip = 1E28F20E41B54C2D1234D896096495FF57E08D18
+uid           [ unknown] patrice.lumumba@example.net
+sub   cv25519 2016-06-22 [E]
+      8D0221D9B2877A741D69AC4E9185878E4FCD74C0
+      Keygrip = EB33B687EB8581AB64D04852A54453E85F3DF62D
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mDMEV2o9XRYJKwYBBAHaRw8BAQdAZ8zkuQDL9x7rcvvoo6s3iEF1j88Dknd9nZhL
+nTEoBRm0G3BhdHJpY2UubHVtdW1iYUBleGFtcGxlLm5ldIh5BBMWCAAhBQJXaj1d
+AhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEBOVY2gqAg0KmQ0BAMUNzAlT
+OzG7tolSI92lhePi5VqutdqTEQTyYYWi1aEsAP0YfiuosNggTc0oRTSz46S3i0Qj
+AlpXwfU00888yIreDbg4BFdqPY0SCisGAQQBl1UBBQEBB0AWeeZlz31O4qTmIKr3
+CZhlRUXZFxc3YKyoCXyIZBBRawMBCAeIYQQYFggACQUCV2o9jQIbDAAKCRATlWNo
+KgINCsuFAP9BplWl813pi779V8OMsRGs/ynyihnOESft/H8qlM8PDQEAqIUPpIty
+OX/OBFy2RIlIi7J1bTp9RzcbzQ/4Fk4hWQQ=
+=qRfF
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/tests/openpgp/samplekeys/rsa-rsa-sample-1.asc b/tests/openpgp/samplekeys/rsa-rsa-sample-1.asc
new file mode 100644 (file)
index 0000000..382d4e6
--- /dev/null
@@ -0,0 +1,38 @@
+pub   rsa2048 2016-06-22 [SC]
+      5B83120DB1E3A65AE5A8DCF6AA43F1DCC7FED1B7
+      Keygrip = C6A6390E9388CDBAD71EAEA698233FE5E04F001E
+uid           [ unknown] steve.biko@example.net
+sub   rsa2048 2016-06-22 [E]
+      4CB4D8C018C57E60EB3847901D777619BE310D79
+      Keygrip = D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mQENBFdqP+gBCACoG81sddF9ZZx6TsN7lenDxs53wqJt1bawToXZl6qJ+hO8tMNy
+/aUgaqqi8pC5FX3HlSRQhjRFDQXq4jR3+jecFK3wfwmxTKXMKhN52zhSIWClED47
+56B3wPITuwAG2WYFccClhrtWX8j+wBK5IpLVVAXQnORZLOP7fzUZkO1KDu3bP4D6
+f1LQyatIzgS08dnlp6WvsJDrkUeGY6R5smpx9f+PqBVfUVpmckbMOR+BYPJtplZT
+0lez4qWsmdWbqU7ZhdvnhMGcTbBbk9WbfR1IJptigeuK8vTU24Jp2FQj6iIBV9OD
+jUfr11EJ6W3TvHaWuddd0hfX9DnyH9rghrDFABEBAAG0FnN0ZXZlLmJpa29AZXhh
+bXBsZS5uZXSJATcEEwEIACEFAldqP+gCGwMFCwkIBwIGFQgJCgsCBBYCAwECHgEC
+F4AACgkQqkPx3Mf+0bd5kggAphS7UDycKadfaRH5JENmKXeI+UUd+E0iERwv7eXq
+RcgjNK1oHQSXN+ejDEXzZv2fcCRB7rWEvEXL0pCtPveyzDAQJdhZTRVgmfCXTr1m
+9pJfVC3B20jgx6ZxZO8jKDL+bqvufWJczWDT0iHP0Jv04SqASLRs2JRPy+a+w3GJ
++DzG8orfAKiIE1Qycovr8Ol+jdo9ZV9blRA8/j4eqZYg4b7AOf8/mDyXsx3xzSPV
+uwkDSluhaOrsV8N0suZ51rfdpapv6VJsXlyQbceJwwgSt2A1n2Sw3ZINwpO7BODy
+wO6J44751+qY4cmap4NItyqGQTT6TUEL9ANfrZFmPWmFWLkBDQRXaj/oAQgA255C
+UJxFEKLVwEoSgwZqXd94AhjGUbMY6NXdFj5cCq0JmWZrbpT/5OblTrymiH1iLmI0
+ymo+/s8vh6NtB98dhr1syH3asNQfXZRfF+u5X5hLDNPF4sUelsl4+EUef0Hbc9U+
+e+8F8A9TMxELSqQ8Ul3Hu42hc+/ugkc1G/8++Sv/f60TqWcUR2GmuiAvkuS1WmdA
+TMhwPr7vMfssV0X0mboz32//b/UfuOyctso5FM+bRaKrEJDQ2WDg57yqnaqsKEga
+jW0jElpAVIn792W6YWKOk4auYSpO5f7BVs40Z+bxKGxiH87z9fnmlYAsQwPOOxZw
+WaCSrReeheK6c6emAQARAQABiQEfBBgBCAAJBQJXaj/oAhsMAAoJEKpD8dzH/tG3
+baoH/0KI3pIUiIYiLESGXqF+s/W2BmGNwdkYldcyFwkXz84VXoG0B3k7nrwT2DOJ
+AEeToavzd3J+aZ4PmxBRAMtDhah0wsMXrwCI8y9Stmm6PIssnu9IP9+jgr4IkKIR
+UB/Wn6nzgseaNd7vN4JChCyLSvF+vLd3D56Wzq+hBjybaE+zcEusVLdKYDm2i0YC
+pkBkmSuC18lLxhNC8oSCCvVOiyw+TqGHhLnrpA4nGi0MLjAR3OgJ5d/TclYgkLcp
+yOupg9GplQsAZUFfQPrY80SJuN9ijBp4xtA1U+WCGKh4ySv1+odpRjPX3eOGUFKZ
+sJRKpZupoGWfVN78wm1nPLBKTvM=
+=6N/A
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/tests/openpgp/samplekeys/silent-running.asc b/tests/openpgp/samplekeys/silent-running.asc
new file mode 100644 (file)
index 0000000..e7c6db3
--- /dev/null
@@ -0,0 +1,120 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v2
+
+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
+=tU5z
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/tests/openpgp/samplemsgs/clearsig-1-key-1.asc b/tests/openpgp/samplemsgs/clearsig-1-key-1.asc
new file mode 100644 (file)
index 0000000..4673c40
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA256
+
+You are scrupulously honest, frank, and straightforward.  Therefore you
+have few friends.
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iQE0BAEBCAAeBQJXakWmFxxzdGV2ZS5iaWtvQGV4YW1wbGUubmV0AAoJEKpD8dzH
+/tG3OiIH/18NlMSXXRFRrxXq9OZySzJxgLI7BjGilRTqb4ALeFzNjmCwu3Y+Gkdg
+t7NjYjSe0erWiKYDEmALICwcpmSmXHA//gol3QkHJKIlKQGXJP1qLvIde5+lnK8K
+YVwLKLBQBQtlGMkMXPdUEn9PgzSoBFoFIqrzQmAdLO3yijSdm0Mzl9wyIhtbUXk+
+VgX2d/6DRIwcKcFoX2QbFlM/z1kdrS6cOYFbJWavEpLDz9ON8Q8a8uqcBiqRlSpW
+eGOMMsysJs+44+qX6uE3hu2KJE9xvHwhSjJOxqtw8dN3KZ1+8IkxsDrvDAhn+Klf
+Hbtj647f/iTOF88o1ihO7goDi93Bpv4=
+=xAv4
+-----END PGP SIGNATURE-----
diff --git a/tests/openpgp/samplemsgs/clearsig-2-keys-1.asc b/tests/openpgp/samplemsgs/clearsig-2-keys-1.asc
new file mode 100644 (file)
index 0000000..0d7823e
--- /dev/null
@@ -0,0 +1,20 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA256
+
+"The geeks shall inherit the earth."
+               -- Karl Lehenbauer
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iQE0BAEBCAAeBQJXakX/FxxzdGV2ZS5iaWtvQGV4YW1wbGUubmV0AAoJEKpD8dzH
+/tG3g1AH/iQakK5FoXpNQs6Nj9NR4NUwtIPmlLS/Tas21CDs1Lo1Fum1gjU0VUFN
+63+FTnbRg8nXfee9RPddLnec9lYWVqWSkggTFER8qQrj/EurltLMv/tHAZ+B0ueI
+mh2XkNHA6KXu3DFipAXQezWaUqi485TGTY6Qv9JtG/plOZBakcRTgCSAamyaDPBA
+PHgp85bPf5Zu4aFRBfmJp+IUH/EFLNFIHNXpYyZZy5ZdB3GuhAHGFp6tlpRFk4Z5
+vRU9BtdoeiIeoRHp4orMESGlbeZxUXG3CCrgzVk0e1pab0NrehwQ23+axMxFipya
+t6mi8Zrxpp7eFc9+ozp+7r4cH//uw8+IewQBFggAIwUCV2pF/xwccGF0cmljZS5s
+dW11bWJhQGV4YW1wbGUubmV0AAoJEBOVY2gqAg0Ko1YBAKVC98xZvGsNoaq0yDHG
+AJKmsvjnc8z3qmEHzGtxOQCiAP92ffXZr0EM4qNqbDR0EAws9qNo0XlDPcm0LDxy
+0JVcDw==
+=Ta4l
+-----END PGP SIGNATURE-----
diff --git a/tests/openpgp/samplemsgs/clearsig-2-keys-2.asc b/tests/openpgp/samplemsgs/clearsig-2-keys-2.asc
new file mode 100644 (file)
index 0000000..992f2ba
--- /dev/null
@@ -0,0 +1,20 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA256
+
+The very remembrance of my former misfortune proves a new one to me.
+               -- Miguel de Cervantes
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iHsEARYIACMFAldqRlwcHHBhdHJpY2UubHVtdW1iYUBleGFtcGxlLm5ldAAKCRAT
+lWNoKgINCubRAQC0VyMKKFXWWxLOwCFO5ovhONxq2VLQ6c7jklZt0AAETgEA8ikc
+doPxIamOCta2QwgS0JHPhvgmL98GWM1dMLfD3gOJATQEAQEIAB4FAldqRlwXHHN0
+ZXZlLmJpa29AZXhhbXBsZS5uZXQACgkQqkPx3Mf+0beYKQgAp60uW2OmVAyaP2MC
+F6alWqWVkxw66L6QW6ciOpiuqjEoc9TN6pNIIP+MeSPu+SE71kw4nD0Vvu5mgH/2
+74dZMf7vFX3vERL/g8u7lTOv2GkXyKpFKAwvMxqPJ7zKUH9z6LxeBc2tNImjQ4mS
+7OL30n+SPrsY4FR3BS/d/EY2y+L9spi92oiJeXjgNHH7iIr5iWiSSXS7AwBla0zu
+r+mkX2Aats488CEfENACugg79q7cNLpUioeKdOHcqDxCS9wSpYK5Y2+IBqmFEv6t
+DKZ1iZnLlk6rHpkZ8aQi96PFbZVZPGnxsOFKkNPWwHjniKeJzoJwd7FqR5i2vrsJ
+UiWYwA==
+=gWAP
+-----END PGP SIGNATURE-----
diff --git a/tests/openpgp/samplemsgs/enc-1-key-1.asc b/tests/openpgp/samplemsgs/enc-1-key-1.asc
new file mode 100644 (file)
index 0000000..bd65330
--- /dev/null
@@ -0,0 +1,9 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hF4DkYWHjk/NdMASAQdAPDV6Y3JTfAGDX8pfZcT6YggC7qV3g8B1ezijcfIcdVAw
++hCFGXS1EikBbZ21v79GtGh6Wp3fmyZFRQcsJZciLE/EFcbf9Mv4Q2qfRhKYHlqj
+0lwBRYQrwTJbMNspOwd2MidjYYUxb/02PNiqZSrWUeX0iPsgHFToJol9RVAqs4Zz
+bZNKL6y/GeRIRZY12Lzo2TIXSLfjvbMTdkoz53mMKiUXsi/fCKXkTmgIheni8w==
+=kmqY
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/enc-1-key-1.gpg b/tests/openpgp/samplemsgs/enc-1-key-1.gpg
new file mode 100644 (file)
index 0000000..6f0fe4f
Binary files /dev/null and b/tests/openpgp/samplemsgs/enc-1-key-1.gpg differ
diff --git a/tests/openpgp/samplemsgs/enc-1-key-2.asc b/tests/openpgp/samplemsgs/enc-1-key-2.asc
new file mode 100644 (file)
index 0000000..e9e6e70
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAx13dhm+MQ15AQf8DKnGFmadCHP3k8blxdRa73pC3BL0fn9YSp2+EvKP7n4Y
+KsVHmKSZ43RL2pq24y5CImLCu6gPkyFGzTn/vmxq8E2Ul8WOvyJiEuRTczNr5NNs
+rZiF7dRMSjeZXCEHme24XIXKGzbnlkALHxh83GpgxVmLqKIlHEjgXYn9fneH85M4
+KTBxIxpAhIKzninnGk2ikmAS2C6z370tRLYP+tQ6gcP8BbehCZFM+TRqyS3aXjdq
+WaV3OgY7uWzj4P0PBXBWx0V829tfgRF9Z70Zx+HA1BpOqvmOcsztah1Jq/pyAaeR
+7t2FunUZuUwbBIYg67/cxStYAXF9ih70tjSRfYBiotLAEAEvZfW1G7lMnfFCWxx8
+S8L+AD+BEdycI/kUZhgxFVde985CSYcpIcQZE4IuTYCoc96ZXsvil5Zlf5I//KDz
+toq+bxa+VU4Gr+h4lbcq8Sj8OPkx11/P4dOyydiYKLqEThig5l/h5IiROL8AvIMf
+TpNhu8TnECbjaEDaDt3RE3vIFP7ZV8zfpsibSFDaK9K0UhniSt/wF4NekBltUcBc
+kozlxWbvQ0k3A+xl1dBCBEpFaJrywRYFvz2sY5ISJS1X3ePJ4c9fsPXePTiy9a3W
+ItE=
+=rFeH
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/enc-1-key-2.gpg b/tests/openpgp/samplemsgs/enc-1-key-2.gpg
new file mode 100644 (file)
index 0000000..c62b63a
Binary files /dev/null and b/tests/openpgp/samplemsgs/enc-1-key-2.gpg differ
diff --git a/tests/openpgp/samplemsgs/enc-2-keys-1.asc b/tests/openpgp/samplemsgs/enc-2-keys-1.asc
new file mode 100644 (file)
index 0000000..abff596
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAx13dhm+MQ15AQgAkI1KV+RVcuDJlzwXShDT9d2r+1GlV2r16z5vp0aDLETz
+Ga+OCTSiDR8So9xqM8kNKp12t2OrhmIerYu3dHQxZAWuqbhj/xkxfh0OyAP2wZb4
+MtwXIcRKWgUz5pUPYcp/7+Eo/dlBs1QaqxF8Lnh5jAlpxDeQvfSgjTZicZAS0rtY
+XONLWaX4nuuHb2DNrQWLDsMvDrwu8fJLPMNy7+tEzECs1G7Tv7D9xu/QHbGw6Zvk
+fxjWlLsD2nUQYwn/GpqitD02y7BHDoZKXIO8GccHdPhPOxZHLCiGIHQ7r61ResHA
+3SlqEsNF9OV81RaIg55ndM72ZLbDTC8ZQDIu/5cXaoReA5GFh45PzXTAEgEHQIFu
+PbA2WmzBGnzmBfXmRg8AVKE2JVvSYLjBynfTPbtKMAUbz9U2grH/0BdZPWaGuYUh
+HNPg9vmmzL5Ch3rSSunzhtxadesh/Gsic9ETkFz/d9K3AVzb9WEneFuEkk43lJAu
+X+btUyQ8rBhkmBQPorvZN+1i+NL0XOP3UJ0iIpo3bn/J7Dy9IEDojQAFtdOBuw6F
+hbWOMoRVodE5aA6JcRDR2HLj68X3TAou91a8krHJ8NAK84ilrZd07XEwGtNbaom5
+rZK9xNFIUV0Ddog6r5rJ/pqsN6o3iEYI2uhh0KYntbIHrRD05ZWRCXhQIGPb6qp8
+wEEydtbQpfJFRru8q7Y0V6MlzYflxI1H
+=m6X7
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/enc-2-keys-1.gpg b/tests/openpgp/samplemsgs/enc-2-keys-1.gpg
new file mode 100644 (file)
index 0000000..1485b04
Binary files /dev/null and b/tests/openpgp/samplemsgs/enc-2-keys-1.gpg differ
diff --git a/tests/openpgp/samplemsgs/enc-2-keys-2.asc b/tests/openpgp/samplemsgs/enc-2-keys-2.asc
new file mode 100644 (file)
index 0000000..ec6202c
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hF4DkYWHjk/NdMASAQdALju99o8iXdJNYTuUNrk3ZgfLNvw4GuaLed/2PDLbLUEw
+LaFnwh5u4djUOPPtZHbNzmJimOobJxYg3gwDew3ERLBqweQqRcqFaypu9+Ss86Df
+hQEMAx13dhm+MQ15AQgAwHCbQ5TeyLGsrs+oC/dB7AZphqWwsSoVXTuxAi3NPbEF
+upvp3mu19HpBJFXijsjysaMbwUGB+DRVhMYwAANfnJJ2oxltNbhMeGic/vRsCjHx
+cJhjv/T0Jc3Yuh3YFlp4V3wMiTa7METMBL/2CQtT+MSQbBubkegcNPBkB5ss1civ
+WpQckerDKtv9ik0+gvYCgHw0wLyf7UmHRekiJigUats0IhEHoZYv/qa3kvcmJaKV
+WffHsOwxoS0jCwj15eV2YHQVJp7nnyxXlX9E7z4gzjxH4MbXpi+tVvBLGM8pHEg6
+EJ3U7koABqQ8446CnWC+OJKWO5cHoJjkOSCGALDoENKRAenz/t9qGzMWPInAx2iH
+lNg2brHS7UM8z53ESeqpYfaHS1QiMvtZWo8Wl9QPJa8vfrDw/bCtNALYU/OHw95N
+k9E+/JgWk9oQFc+syNHDJzw0qfEzblxzng5/d6W8vjggFkIrKwMwE1/6x1w6ZLoV
+MYG0TXjnLNBGzGCFRSoDx/RuzybgdDSySV/6OFfPAMSo1g==
+=iPxe
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/enc-2-keys-2.gpg b/tests/openpgp/samplemsgs/enc-2-keys-2.gpg
new file mode 100644 (file)
index 0000000..a2889cb
Binary files /dev/null and b/tests/openpgp/samplemsgs/enc-2-keys-2.gpg differ
diff --git a/tests/openpgp/samplemsgs/enc-2-keys-hh-1.asc b/tests/openpgp/samplemsgs/enc-2-keys-hh-1.asc
new file mode 100644 (file)
index 0000000..87822ad
--- /dev/null
@@ -0,0 +1,20 @@
+This message has two anonymous recipients:
+
+  public key is 0000000000000000  (steve.biko@example.net)
+  public key is 0000000000000000  (patrice.lumumba@example.net)
+
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAwAAAAAAAAAAAQf/YA9Ch/xoVYQmAEyo+9VqQxlvgYt23G/Vid3jgn0DFGp3
+DRyP8CVEn0ctGpb2kp8Cdgo+SMlO4WCIeVpYzZDCvHYwXSjh6EHMoLL/FVxyUh5q
+fXiyXl9692r+ms1qzfqJvVSSAjn4PzH31gFG6iQIz5E0yPRpbaDHA+7UlofP4Gfs
+AfidaVJuu9T7OIU50G554Lsjc3oXkr/m1OJDtNVABkkKLsC/bkVZKC6sTxFbmpXV
+mYJqq2cBFC5QSE1NO3Gcj4jVhP8CWE2hymIdFtk0HBGiDLQESw9OUmF/MHD6g2Fw
+NwVcH1pfzxXQYvygPPjaB0AiHR/52jsBifK/fG82R4ReAwAAAAAAAAAAEgEHQHTC
+vCgH7xW/vw5NRqRLSGarsauU9gY3x9aslz65kmYNMNmfnuedeyTxNj/X2C99/iYp
+BmofHiCYMkFjd5C0M/+mbGVQNdFwLG4WSSwXf3PkZtJoAXmj3A9opaFDmv51rs3a
+05IOjuHScOpUSKbTCWLY+rrAlrYSNQ0ZEvBdqFUXmoKIrUu/BLBPw654zrxTrFiX
+7cLcUlALJdQISuAEktJVb2E7dsrVFnLQsjJv+0EReH5FfSJRzqFaWjQ=
+=NW7s
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/enc-2-keys-hr-1.asc b/tests/openpgp/samplemsgs/enc-2-keys-hr-1.asc
new file mode 100644 (file)
index 0000000..00d387a
--- /dev/null
@@ -0,0 +1,29 @@
+This message has one anonymous and one regular recipient:
+
+  public key is 0000000000000000  (steve.biko@example.net)
+  public key is 9185878E4FCD74C0  (patrice.lumumba@example.net)
+
+
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAwAAAAAAAAAAAQf8Cipp2jtLlN1R/MucnvTxzDPLqRg2drOqWkGMoKuUlSvC
+OAzxliOgBLC9TfLxf/RP/v5KkRms1ovrXsm6bMuE59j04koJ1+K11IzO0jRSaFAI
+Ij5RM3z4v27dAR7leE1x5QKrltyScxNA74CAXXEvzm/kyGl+efLeeeZcOrbGMxSz
+vm2n9rc054bkqkIdJmqNkPlynD2Qo1oJUei0GAsV7s1IMB6dtqlGfSUJqmzYkNYt
+pIRd36xq60m74BrincO5xFNbvaSleA+nzLRUVig5KpEODJBGCpraVPQsQjoFzR1M
+CtjVVYUFo7s8QET87Wj7b07v06WpJ0e1Nt40zGqdtIReA5GFh45PzXTAEgEHQIA9
+Rwe1OkhWabVrw90AN5lmcTuruB2ANiW4pTiLVjpIMI1XNV9Ob1VysEUIqPIazZuF
+unlbIgU1sme+TVLV3/P07C7xiLEGUGUlfOjp4oiIqdLBBAEwtSO3m58GWZurA+aD
+K30EiHugSCdTYYdKQ6MbXNZxeLpCfslxzUAGwaXZDRemWrbTrBYXcC2+3Wz8R66S
+a9phYUlVSWCODZkvQvKARaxdvLdqZWRqRxFy3D1YYnYEvmb4thPUuxAiPb/2pTxJ
+j29hTuKDm3XJ5ZDDG1qlrPx71v1uBxUKBSZDd3YBPMxaLdia2fEmTYjnDN1Q6mzN
+NicMjmQo45ekA/QOeBobXMEPFsUr87LCY93PuPTDgQIen64ynOsWsVXv3kTM9X8b
+dmvj3MnKIWzDSIDXOKYvjnP4orCahHp/1qB/7obh2xoOS0qSMAphKaTnVhPAAQc5
+d5scPLWGe9GWKLpo7eh7yWrk04ryCbZNJOHjaKd2lwAbQ8ip9pA7dy387kUQsivh
+iOljf9oHPhRY8KrcIZzBJiyasGQMox0/wabQtnPHVqUDJdruaPsnqgU0P1Ojc17a
+b8cJYTk22pofDEs7oLcUeYZ8iTRpysSTCxydJwEmsj9n1lDW5M69KMlKLL0rZ0nv
+9nh2WbuwEnA71DzFq3V++dA6+geno5/yCyt/qROJ8I7zqC0DPiMfdpIfOBsC7n0W
+8hpDIps0
+=LChh
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/enc-2-keys-rh-1.asc b/tests/openpgp/samplemsgs/enc-2-keys-rh-1.asc
new file mode 100644 (file)
index 0000000..1d864c3
--- /dev/null
@@ -0,0 +1,21 @@
+This message has one regular and one anonymous recipient:
+
+  public key is 1D777619BE310D79  (steve.biko@example.net)
+  public key is 0000000000000000  (patrice.lumumba@example.net)
+
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAx13dhm+MQ15AQgAmDRRzNRfv/NXeJzBLOwcmBjWZ7UZAdr8Y5uqvOEdjIyj
+XQlvH56/lNVa4WsGcxRWfNucFs78pxqAY3YulApIs1o/+WheCpPEvxMJ5Z+s14rg
++jV0H+oW9UkeIVCKeLlHrosbUbYM8cvzsHdNFm1U6MnqH1DNiyTtwgzA065kyRDQ
+QwoCKf3Bsc+nmbfuWafdWDRwNptdE13JuRoFEd/KxhfXDhWF2r3ynM97erADTYMB
+RXzOAuNxLxrgdjJ2KJoJu6KRVGMJk1ermzeV1wv3bnfME+QRtZ2Gzu3heAktR9Bj
+gk4dOkEdYHQi7aYpoRaeWtK9An8FafLrEsbyYISNqoReAwAAAAAAAAAAEgEHQKD1
+Xk0mkgt/BPeRvR5giCsmMjniGdan99NWiiMJpcNNMOP65NimgxyOYDTbpsGl/tHY
+qmNzNy1Wk1/ZRRAr4+K8ITs5lmuoDeVVkGQTE2ahRtKEARtFMKoRDYO5dEgadlnL
+FdigDutyPLqVMaIwmx0HivjfXWEYyhBSXc0wwEvPhH76aBBOAnYZKKsLJVx+GoHp
+Lxlvdz6CsOOKfgxY7PBjCEpS4aOtIYNenW6fHMYBVTrOXpNok7Q18rx1yNOxvT3X
+g6zTetpqqM2SJKgSgRNsOobCDhqr
+=jW0C
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encsig-2-2-keys-3.asc b/tests/openpgp/samplemsgs/encsig-2-2-keys-3.asc
new file mode 100644 (file)
index 0000000..e563e8d
--- /dev/null
@@ -0,0 +1,35 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAx13dhm+MQ15AQf7B8SvOp1oKADLmqzPCJp8kLUvt2oemNHYvSU06gTlTT8m
+DGJnA8a4S0+3q3Oqt/CObBX5tNr9KIB3OOgL8LujUffFVo2A6qfBWYnpyrDeJQOH
+idilyZvAu4CdovVvp+2DxAfBYNb0jinIjZEcF3YuIFqk1o5n9Jx0C3LDMgQwjKkb
+xEZeUkjt4i9Pb2JNP6+LQ8deDwLLcpS5ykP98MTHgG1OGw5QX1xxKArEq4YJXye3
+ubQBAifE3fGKswGiV5UuwrP3cB92KdtqYLCckrheDa96YJp7kZNDPFds4aqaD5i4
+Ps/bxXeZmeybhgxTT8Q1Ld7wUd+sFV36uRieHOMEIoReA5GFh45PzXTAEgEHQEyw
+MoBXgqtfF8+TdiUcIqeH+eXNOHjqGujt00BRn8JTMJNuCXoMZDmu45AaXZqiYxov
+TTfDyKGLVvaiTxEJdl/ty55X9C9ANppdFm3qZGZ6GdLqAQBRsaHHa5lSfUBrgJXC
+DLidkt1TA0u7owjuWRkUDlzBt3lEcgYEFd6c2zy3wxljpU0zB/gEmlEQiQAYB9dR
+alrnENgo93aExGoTW0LgsZlf1n8GuPCyK+3m+1+2ryr3qNreg69Y5HaW3aV4pEG/
+mMnxVffq0sJGtEQRAx8dESImO+jPVmdKx6JcGWQ4B3RmD3qzOgbGwRoeC+C/isV7
+t+VEC0iOlC+QyK7S1QgxcWwzl9ExSs1d+BM3cwNlwe2mLckgsayEUGXrafpifiTR
+w1CSyt25fb23iwOu1XZeHGnth/XAAJQcUsi02E+fpMPyS4S0v71PBn8By7iXHE8W
+stFZMP9Gcly6lh9qOFg108P+mIWOVj7xtCUMl0RRwxS2hrKypucJtPSmVZ6EgVok
+8j0tNm5nSjLzQ4A8I+O20Tx0sPBjmvH3IbMNCvjAQp6gXYlDgiHv2zxAgHwNJjRh
+ft1AJy/61HG3MtRNV1QP06l6tofGAzP4gBBqLJkVcK1bCGpx17LZ7t9GI573Y7Jr
+CIFN+CUWqzN64Q90IMDFwOl2ghQGZsIRh0jG3wOjd3C5cFo176BJiAq5WVelVEO8
+A3J/xMofeDdAVTkbpDpW+rE66I5dBwa8s9ej1zTpM0hmbiON+Ld9cCW3VPuDjjj3
+pAndSOcbfoq0Qd1RwshQVpfJJYjuhz9qCdlp392KWSvwTD/YuMIZ+nudgxk9Vbu/
+Z3ro/ggyH0FmnaJ53GnJ3NjsiJkSbQ21fSw0zJDNabpwdVPSzSvPtflh1qKiU60M
+eNI/QI6lKyZzwFCuAkcZKGWGQrDLjmbRtSMJHAw2cT1sQQJ5XtciiL+pOixawyNE
+pTnYI4f/983JewwweUwFJ5GkD/uY6hM10b4OKpjjm8rfpBVmW8rsuAGa5sSOAZB4
+xt+u6/dzVDCdQKtYV4pQHsHahAAkIGT1pWi0PMyWM3deo3sGaiCGcpM7qpO2qE4b
+paimL2Un0J1qPkr4cbykzzUx4U1zgHUHKDPhmSEtqLfPEd2DjUHsAvJZJFER4lD9
+yursATLzunEYiWUTuE6DKjcfQYPrAmat/mzquvf+oV5YgPvcY85U3t1XeyW9Zyip
+APYSJdgYdN8Wemh21vvGj8B7xnWMaJlcbsCbvuu2GALUGQKbhYzV02lMPSbEUHRH
+pRI8NviMcR4UD0/FK7g91I7yDqX6BLBckUw+W1KYKqVvlcMuDUOc5nQTxWXrPWJu
+o6EU4sD4bDaFOdDW8cuSBhxiifU+I+1s89p6+6M/Qwenh0hTvUsQwpUx/cXwjNXT
+0uRaIk/yjbEZj80lTKyAn1TvlJ4A2vYjscqfiiVYBU1/enfnsYgUf+TTK2qm3TtV
+HiuLLNvE2uy2IQfeZ3DnzZlMoCY8PA67yQCxJXR/hVX+/hzlZ0PoPylkYejs
+=yD/C
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encsig-2-2-keys-3.gpg b/tests/openpgp/samplemsgs/encsig-2-2-keys-3.gpg
new file mode 100644 (file)
index 0000000..b262d45
Binary files /dev/null and b/tests/openpgp/samplemsgs/encsig-2-2-keys-3.gpg differ
diff --git a/tests/openpgp/samplemsgs/encsig-2-2-keys-4.asc b/tests/openpgp/samplemsgs/encsig-2-2-keys-4.asc
new file mode 100644 (file)
index 0000000..1b63617
--- /dev/null
@@ -0,0 +1,33 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hF4DkYWHjk/NdMASAQdAtNe4V9DKNR+N65wm9hJk8xRewYZPhmWADCcFraD0rnUw
+MWX9tj1E6GIKEhCAMomt/PoboZ8ncBJ4JZ/x4fltX5qsfIZkVqILolPAzrp5EbeE
+hQEMAx13dhm+MQ15AQgAkQn04BIdVZ6w0q13WfIoSepk2aQs39E6rmfZRUUs5Axk
+aTkHLQa3jSIpWXtSdrm5DBX0rhuNSiFk1h2pwc0OSnIhl6jxrjX1TN4dbXrtaJUz
+rguevhF72sfksr7p5sy/yFF1DBv3Z6MRKyyt4FjpbhzczDU0BD4cz0IGMb5tHLB0
+kTS1pJYtkajuWEGiyfT2dR1g0SdNoVwXiu+Hw+buPabAdjgVKocyGmdbYr/ip88t
+9o9AayTN2BH0z35YBwpdULcoM3Dww+sTcO2sG6xiy7E24t8RPFUQOfFm5vfmI8EH
+Zy4nId6ZkGEdkzX2UkU6FvX5vvru76My07nqKENDBdLpAXp08EPSUkTgnl9d7Hyq
+R1jMFiML3/QtMH7azdmjKdmkhrYPMgNoAiK1lO7pw3dU4eHfWDnPUWw8y/WHmoUT
+lxtZunT8GUh8ZxXl+skOqy2UXHPPRSN602oqma+yYKZrzn8hQm7Rq/tbmFPRTE7V
+cPCuRD0u3Rwnhldq//r5w6AgG1jKu0gXXzLYcubEl7S8fvXG/udSg1ASjhdhbYPD
+larTKCby1fESurfhwFnyaIGPknpzGooGFU7sIkrjilNPfVGv8CC10yMp7jOM7nXH
+hZ3w6JNHzB3UxlVjOjUkXFRxm3X4ydNXFgrp8soGyOnhjcUcN8A8gIXJoDQwB9G1
+STIilDwsBzFJOZfJSdy0/mjecvqT2slFsl3fjr0h0M2cTsYw1Ws5iG17HTJBVjpW
+frmWVjGVLRXkLGkumNbLpGxImlz2wlvuSlk/mqgrbRyyz6ifEpQc2o7uFvT6BGTp
+pG6qPafKLEAOkfOZGt/BKMsWESoOXlIa5B8B/4/t8me0Lni7RS09908ait1poKEM
+cDYNPtClQlBLJB3GLxPDDUT1WNcEBc+vScU317S5BRgDXBdao16DLzoIoh0C8kYu
+JBIQvXYLw23IBilHxzv0Fr/ta2joAUOnojNZMAaOawWj8i8/EwO2Hl0epx8Ww3ft
+VMnCF3nVuAIhjYEEzYI90dzA35lcSyEcBDXKBUAnOLi0LhwySi3rzM/d0yxdDGZH
+oPw2JQWpgCuv4OMin5YSRowUPhgFmltNc9I6qgVdy1vLKndC/OnCCtQj2OpUrYsH
+l1H3ADreaiunjtCrFTGYLey4EK6koLcb+qdKAOkRTaH28nRQGEyzZ4U93mbTsNmJ
+nAW4JCbZtMap9on9koJwiopEA+ONuktCD0j6RSAC+HdyhwN+MTWqCtTbO/tIvaqZ
+HtAlhiHk3GSi/qaox5dLKZqu5pa92OwiZrS6vS+dWTQpmyCyHYZcglsaRiHAGIEB
+3MVPKMvLgp5wV9uuSnr0aXaXoyEXjjMHbP8UnAxojnVxGJTOzsijE59ovddLgqUD
+81jYd4K3XIX+aWy3GicJaiAgzOYwJzBrOLZFGIlm9HkXKwM2gqd6TNjKQHxS63o0
+H6vXirtZmnRfA2SnmkGACbwTEa7vKARt4W45rXXk1GiQcxV0U7QrdQ9jMHIPtJF+
+py8jqdfjnNsUNM7PyTVjB9nTk9V3BkwIjUs46R6LqElZsAQQGcVo/EzBoPhjNUaf
+K+I=
+=kQLr
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encsig-2-2-keys-4.gpg b/tests/openpgp/samplemsgs/encsig-2-2-keys-4.gpg
new file mode 100644 (file)
index 0000000..940a964
Binary files /dev/null and b/tests/openpgp/samplemsgs/encsig-2-2-keys-4.gpg differ
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-1.asc b/tests/openpgp/samplemsgs/encsig-2-keys-1.asc
new file mode 100644 (file)
index 0000000..649921e
--- /dev/null
@@ -0,0 +1,18 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAx13dhm+MQ15AQgAiZPJa/zmtJ6cDpHVze6zBS+4OCbGeEpzcHBkpWiLKV91
+6CiwLTtL6Fhs7P/i5lEUzWQnRp0IGmUe8Ft5tugAL3ibv3Xm9PstXPZ2Q6EGzDCY
+98x1aQooSuiUwIB4uQ8zFqA2TYGNfRcDCGdHHLpWAps4F/QkZkQGEWmy7KQZetc+
+mLP6z04fQz5XemL0MaJcarLRE0OK8FI4+413DqQB3RyZsMFiFDAY46g3rA7xymuo
+Elum8PjMDXtAEpYAs2NHR29okFMinB7rR/DFGabQtzWIJPlgyGOFUVXs7YWj0Git
+SgEje73u8eEYAJYTpud1zup/KPUYOqJzyIMvOHDMz4ReA5GFh45PzXTAEgEHQGSH
+2coczePYstzayq418VjtNF+0ohoFKm8lrR9THREYMFJ4oA6/e7r3g38CWlb8kKxN
+butxPKCcO2OjZYU5PZMk03CwbpSWM0FTNJEzXfqdKtLAOgHgccG9wgBqAbcTejiX
+FQBBsLXRybq8Bra8qW+RVJ5noCav3TH06h8ZVXz/jJMLSUfKt8l+xRQDkYZ88cN3
+GhWNSc1eBOjS8e3JwGYaGs4vuoRVECbzee1DWNk3CUQOgeqZKLoSYHDRwHMpzP/N
+suXLpGTV7EoN4+qOcF5q/6cZV4gaGxgokoCUrM+IYfhOjmqK3lfo9/1GUxppyE+x
+XsWKiUMta3tJ6zhWYJPCZCqIZvzmkSfk3pNtOnsmmhF9gzwN8ehi/FHGFyHc8/gW
+qxx0KsCG7FO4Y514pdoa70KqA8QO63YjxTaFBH858yZr5ORlhzElwctgivU=
+=cWGf
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-1.gpg b/tests/openpgp/samplemsgs/encsig-2-keys-1.gpg
new file mode 100644 (file)
index 0000000..38ff6b6
Binary files /dev/null and b/tests/openpgp/samplemsgs/encsig-2-keys-1.gpg differ
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-2.asc b/tests/openpgp/samplemsgs/encsig-2-keys-2.asc
new file mode 100644 (file)
index 0000000..4eee21d
--- /dev/null
@@ -0,0 +1,18 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hF4DkYWHjk/NdMASAQdA9op1WNWUj4E0PZ2h33tolomYTag75nRNg8qLo/2xfXcw
+QrekSuMoLtkv1KO6/tLIohqYYYdZL5cGadTxlBLyIEj32ISVj7El6DxJrmqKIK3y
+hQEMAx13dhm+MQ15AQgAnY6drrcce7MeloBIECLSbFIDjKOloUT4xtqspTg3GM1d
+wkXtTJOdEm1yLcNQsb+d8ZdZZfYZhotCyMlZ5QQtvf+0XOieb/FlitUI0twAMsj/
+kwjN9dop+KGLZadFoar5A8TBXUz25PfWmwEzz2qSmIPuoIUzhK90B3eGUG6foGzm
+1zEAawfyJ9w7XVAV6pNGJWG2LHSQr2POaMbZs/3iqxQl8p2yb25SlKrg3I35UClZ
+0FC9Hidw8bZ8/rZCyX9KYtHIENHzqT5+XEpaXwN4hBqwpVgUn6DcESv2BAR7KCHD
+ZwRRNVZtUvrftj05UIxAgnSAdK5GAyhLfWjCsH5Q3tLAPQGFdlgyYU9q+hWrrqwW
+1tAvUJQpSW97WyK1Aa9RJOLPNpfU1wzRGzzOuNuuqbL4l9OQktJ81Mihh4IWCXQD
+4mN7+nvltCm13bANdujRvZstGGFefRiwkBlEQq9uQMM2SVXA+JAff+AvD5F1Ofq8
+DPVMf/WDsKcoTTdqJahk/zoX4yFHprS50tO2z0Mb9souX14+AN+JJzAGQaGRlXXD
+TWeEkUXD18HcVzHfooqLUlYYr5zD2f2gNNVskPYH/iP3FGllvzBeQI1NCznAj+Zr
+AdOEXHKOkCJmj2RKnxXeOWTJSczoBlQgIQGd/yP/2TPsGesd4SbqFStYuefEZtw=
+=hq0A
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-2.gpg b/tests/openpgp/samplemsgs/encsig-2-keys-2.gpg
new file mode 100644 (file)
index 0000000..6407387
Binary files /dev/null and b/tests/openpgp/samplemsgs/encsig-2-keys-2.gpg differ
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-3.asc b/tests/openpgp/samplemsgs/encsig-2-keys-3.asc
new file mode 100644 (file)
index 0000000..f10e92a
--- /dev/null
@@ -0,0 +1,23 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAx13dhm+MQ15AQf+KX1A2pYF9HnvwZZU6kmiOKs6NL/d/8Y+kwfiLot5SnQW
+S/2JJm0b7ijyxBOoTyXu8UOqyaPa/eIJWeMqNANExkX83S1hoKfzgrBluzZR4sUB
+r6bZ5E26pn+gy+r1RvQJnxUWMX41ux+DSc+oqf36cZ5A4R1Ai6cD9jqW7vE0KINo
+jn6Od45NHNG16Q7igH9HgJiOXaibHFyiAfV5du0XB0HxpBlBKIBSV/4ewFUzxVy+
+oR4/3F7SkaUtGwcEi+PUEU26KuYz2ltYA9Ex/yTd59YcYbPTiiq+ynGRpOTgB0ti
+y7aYzJVOPWGCKn/TFy69QIoJZgcWTrmUJK39wxFNM4ReA5GFh45PzXTAEgEHQKqL
+epFBazPDtJvYGye9GW9gHMSjuTFuEm3yuo6kPIggMBRK/vWfTa7emGniukdA/8Bn
+hXrpSZUBab19RlT/mDhC8+CBE7MvEQMHsZvwsEWzt9LBAQFgEPLmrwSchnzw5+vN
+bcfeBye2n5STluKZ5IrW4XwZAvmp54w2OI/FDzf5dL1r+KCNiZpcmVO6IVVbEIeL
+eZj++YAPDS0cf/bPfWbyfvC/MLNM6IFICdkdlKQ30FC801Xv4OuXvgctjIkZBEDR
+CkDvkyrIEUtN9jJaAWjP3KopsCsxGtZ/ZPVU2yv8ekPRZ1paUIb370/NhEz9l2kK
+GwmqNm9g6/ekJwIF6kZKoEzncX7cpF0diSTHCyB/CsWc1ncWgn/nktZDsd7UicKP
+ypHScloUZfXDiQBcKV+0p6BxYib1MJOFrRbJTu+0Xu3KjcbecQ/mymgfDlkVUwXP
+QeGaQNUgQzO+iAW1hPH5Qf8eB8n2DlbqsFEWIXG7B3pGCI0eBWPeR/JpuCnIHMTh
+50YOwGqNQLjqRnl6hFi8amSIK5jRvRMzRWYO8TSZaYVh7uLh83cKkSV2e7d2pax6
+CqubZsoiaX71x+r3NaPYf+4hzAQUxPDZET2hTR4GOeEGT14t9RhqMPLTS+f9Ij7D
+/LbCpm6sc6eSmbKXZF/XAPpkBmnRIpgqJuA0TgNBnU7a0NEQP6nsicOpviH9SFEL
+waeu
+=6uha
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-3.gpg b/tests/openpgp/samplemsgs/encsig-2-keys-3.gpg
new file mode 100644 (file)
index 0000000..1449366
Binary files /dev/null and b/tests/openpgp/samplemsgs/encsig-2-keys-3.gpg differ
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-4.asc b/tests/openpgp/samplemsgs/encsig-2-keys-4.asc
new file mode 100644 (file)
index 0000000..8937f5e
--- /dev/null
@@ -0,0 +1,23 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hF4DkYWHjk/NdMASAQdAM+CNEu/KZIBKoKmvE96atl4CEdxThqamGsRt9IgeMxcw
+Te0hTUQf5LrrK9MhGymBcB2nCCy0bPtqVhA8TdZ6y3CH0QYMObkbSbIcVnGaVmGd
+hQEMAx13dhm+MQ15AQf9FcEbvw9ocsmqrteF2Cu6W2ChxrNy6ay0gcDwvd2QfbAE
+muM+OcKrvXhgDikOt3gAv4ES+2/ACzsqIZZJGUVWlrkSXYq9Uon+YX1zeK3BfmOK
+GvfLqc7p9x0YtrC8KEeMaqpd8z5bRhpF0ZPF4WbvZyiauDAa62FJiH/r4YngGLoY
+2hXFNZ2FFHa2EuobUfJUJwfA7VC13IdvqZ76bixrSSjxJjhntiswxYQI+OaXnEg8
+S/UwxR06GT7vOra1O9TGIHYwTcRGQT/3NHcIO3aJMRCHVP2dOLBMkFqkYf44kGeA
+e718nBN1UB7cfgv+n2bj7SYGdlEH0bmmpNTavEsDZdLBGQEcNlkdz3CqdqRhXUek
+hoWzCKTzOhIkoIhdyZd0stBlYJ54dT+9470JogkVqkNCWjAP1svI6LprOAR5b1sV
+m5ar5pCspumNRfMv6oDjXIsjCaux4zJfJV8XO38wmMn30eMPg1CzbKjhqMW+IfXe
+Tn8yxDBVGScIKkmaks6AE1v9WtfBSz+zT8sFe1ZFUMRcJ4+vohYmLVZXqkXGFJu7
+F3j8URhctnGb88h33y2+xglaqptso7XpM91OR17e6Vhh4dNAWB/GdKy4VviVY3W+
+fJ+zoimrPTFmPo2Ag+mveTsnTzmGdy4FHDDQCKE6QVcJPfVcfN0+yiPIOx/XacZR
+ZnQlI9Z+iYuN5yEchnVK65XZGQkdK+4/5Q/QGq7vLwaOHkMtItplIsretCGHAGEj
+XcCeHIY4pVZOd8Of8CSSPvtcaz4+FbZ/cfKXXf1zjdxg5BRkVvBAAtAYqquDUPJn
+qcG7tcUD6pQXVDHq+s0j8BofK9BXjjicrTI64RZw2RYntdbRSqd82offshvF4MJm
+72hIMbg5ExZsvdUa+IcRw49PoX/fEhKkmElZCI+5fsMG/NJuTfAtNjG5RbdgrYzQ
+eR6eIMr6BnY9ZZQRPbuv0te4di55B+HqmTry
+=/grx
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encsig-2-keys-4.gpg b/tests/openpgp/samplemsgs/encsig-2-keys-4.gpg
new file mode 100644 (file)
index 0000000..46d2037
Binary files /dev/null and b/tests/openpgp/samplemsgs/encsig-2-keys-4.gpg differ
diff --git a/tests/openpgp/samplemsgs/encz0-1-key-1.asc b/tests/openpgp/samplemsgs/encz0-1-key-1.asc
new file mode 100644 (file)
index 0000000..cf534db
--- /dev/null
@@ -0,0 +1,12 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hF4DkYWHjk/NdMASAQdAPo9H2rEUOisFYLfLQu91wGJCSIGs9jFiYwQsKlhsZlMw
+itRELU7+unvpPp8bIINqu4X6FP7hDzkZjOlQM/5JS0Z/q2jaWo4av8DCxYCK+yHU
+0sATAZtMvHD99HWEAis3GUlFBzf/jxPBmayNElVyifc5eH4d2pRfCqlZPx9gKX69
+OYymTKuUkkmzCgBxVfA7XPdIdqTmDbSjVwQ2LFeB8hQv6PsYFHY1vqs4xVmeotIu
+pgG1a40+6f8HC9YDNn2lUzktui/mi/VNqDwV9vOHYklGqpVDd81nHAl1wGkAzgBs
+8sYAcQjRAArAPKBaPTCtn6PZF4p4sDcabGImGR8cWwZHb9yxkHIomJRHUVTF1Uz4
+MUANuPQHpJE4eqKHUaE6wyTXyGEqJQ==
+=UB/1
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/encz0-1-key-2.asc b/tests/openpgp/samplemsgs/encz0-1-key-2.asc
new file mode 100644 (file)
index 0000000..a885f5b
--- /dev/null
@@ -0,0 +1,13 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+hQEMAx13dhm+MQ15AQf/WO25gVi//kxCs0RH+BbJ5OWRRkyZ5fD7mYUs6anJ/zRE
+SE/SKwNk4KsWi4ajRR7b7txj7HQN8l6RpjUFXDJwd0onkb5JoCcvVIdaSTRR8z3s
+5tkI/KTkPhlDPN+E5jCllUnJNSLoUwIIMw5Zgn0gRXxZeR6pUCB00+GmSPpoV+6X
+pEk8yuP5gcCFz2uiPmRl6QBezq6QLwlzYS6Kj+m2k2zqgEEgBc31aVnze8FTElbf
+Mm2wQ+w50PVaqHKkH7206PMIAd3Jsv2QP4XfgDDRxOe1/s6dHiCOfnhdrx/Fblp2
+VjluZFc/yL2YfofqqEWAxLLzh47aVN6JLr3bhdAVvNJEATedhlr+GTfhfI+KYO9r
+rZlP9aDHzvMKkqyX4WDD0O6a+698AnoseFVmrrBIsokdIt1RjLcpycE4BsCQOXHe
+EDBJtGo=
+=O1Fl
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/sig-1-key-1.asc b/tests/openpgp/samplemsgs/sig-1-key-1.asc
new file mode 100644 (file)
index 0000000..875cf83
--- /dev/null
@@ -0,0 +1,8 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iHsEABYIACMFAldqTEMcHHBhdHJpY2UubHVtdW1iYUBleGFtcGxlLm5ldAAKCRAT
+lWNoKgINCu0XAQC6VSdsGyTbvFPp5e6BmkmBzPcb5Kex4ar722k0jzhLzgD+Js2q
+Y1JIdjfW4GnFhdzqyUbuGTlk1wNY7Re1uNyD6gw=
+=c0oW
+-----END PGP SIGNATURE-----
diff --git a/tests/openpgp/samplemsgs/sig-1-key-1.sig b/tests/openpgp/samplemsgs/sig-1-key-1.sig
new file mode 100644 (file)
index 0000000..9c823cd
Binary files /dev/null and b/tests/openpgp/samplemsgs/sig-1-key-1.sig differ
diff --git a/tests/openpgp/samplemsgs/sig-1-key-2.asc b/tests/openpgp/samplemsgs/sig-1-key-2.asc
new file mode 100644 (file)
index 0000000..f7ae120
--- /dev/null
@@ -0,0 +1,12 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iQE0BAABCAAeBQJXaky2FxxzdGV2ZS5iaWtvQGV4YW1wbGUubmV0AAoJEKpD8dzH
+/tG3LSUH+gJ++JOZuy5GfHwK+5GEGmeVbex4U9N84tYYAwZOsOpQsh4JxT44IH8S
+OG9OViY9xUaUmeSvVsuDR890RiZtKOXO3hCMwUo+HCDFLXgIXxosLlS55G1vfi8X
+NPl78Y9NFdtwtAkirpOT0oULJcbZ9NItkPjhoxZ16TlgG3GUE6lZzlZJLFAVCw7u
+6twOtPnq1AB4xB49rsIIW1XhCNrajwzBCghhl/PD4uM7ptSpGkZur5uOJ7nLjNEM
+Qo1mF+jQ6rjWA4OrvpmtW482yvNWejAS+JMlhNcP63hlBySjX3tFhGm8tWtUauCT
+3Ky7iF4dFFmhpIXUBT6mMmci4WdA3gE=
+=VdOj
+-----END PGP SIGNATURE-----
diff --git a/tests/openpgp/samplemsgs/sig-1-key-2.sig b/tests/openpgp/samplemsgs/sig-1-key-2.sig
new file mode 100644 (file)
index 0000000..a4f5199
Binary files /dev/null and b/tests/openpgp/samplemsgs/sig-1-key-2.sig differ
diff --git a/tests/openpgp/samplemsgs/sig-2-keys-1.asc b/tests/openpgp/samplemsgs/sig-2-keys-1.asc
new file mode 100644 (file)
index 0000000..8c767b2
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iHsEABYIACMFAldqTMccHHBhdHJpY2UubHVtdW1iYUBleGFtcGxlLm5ldAAKCRAT
+lWNoKgINCgcQAP0f1yNJcHiBvy3nK7SSuzBf1EgSpy/lFlVSjZ1e/7CEKQD/W68C
+Zs8iGAyZplpsXKoz/g7LWSU5z/K3lLWwfre7gAGJATQEAAEIAB4FAldqTMcXHHN0
+ZXZlLmJpa29AZXhhbXBsZS5uZXQACgkQqkPx3Mf+0bdg8wf/ff4tEMfqdwk1dXJm
+4+iyrNvKyCfv/T5W8BVL16wc8jn+80HJkHK/pSw5Rr6nsEf1P00u5AnothUPfUl2
+Yqvjg4+oQYvutePo1uLq0LA1lyWfQ1PV6I14B/dd9rBYdPjYIJJsPjr/k5N3Qz9M
+8RNtDp/rPDVNVHzDbZN77oGE2jokGRfodRo6qnurqU4CnJYinrnzKV4wqrilNKlE
+R2CBieb3riDFUH59PH9S9fHuTHBV7q0HlxNJkI6NeoFwtRcS2f8P5B7FK7VCMrUB
+R46JExeWhvUlY2ZkKLU98bI3TLnFD0aQHRzKgJj8sWjD+Akzf408EmnOIyyf6MF8
+H7uIHg==
+=ErBQ
+-----END PGP SIGNATURE-----
diff --git a/tests/openpgp/samplemsgs/sig-2-keys-1.sig b/tests/openpgp/samplemsgs/sig-2-keys-1.sig
new file mode 100644 (file)
index 0000000..541285f
Binary files /dev/null and b/tests/openpgp/samplemsgs/sig-2-keys-1.sig differ
diff --git a/tests/openpgp/samplemsgs/sig-2-keys-2.asc b/tests/openpgp/samplemsgs/sig-2-keys-2.asc
new file mode 100644 (file)
index 0000000..16ae64c
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+
+iQE0BAABCAAeBQJXakzUFxxzdGV2ZS5iaWtvQGV4YW1wbGUubmV0AAoJEKpD8dzH
+/tG3B8EH/247hq+cJ8eR8eXb1mv1Bdj9SwYI4yDs/xCZ7FIkU8vVSRYQpeYz59ie
+3WZw8Cj1Sd44tr3+viVK682lWXwpHIAl3xUizP+HTFs23tfyH3er7IhDO/aApZ+V
+Wd+0oDJY7E/ztsD3CpU50ptKU9D72CgJT8K1/pwBtivzOiMto/scPwVFNDzGlny8
+FC06j+2FyXFkXCLwvz/Xdk+hJmv8lQRGNxnSIB5bU+0/GLEd9wJUFTV3WSs5enEM
+zqtGBh6v395BXnqrDHpOmT+EkWrpBOSo5vkPZrbN4bOC9nKSa9isCvU/+fjHW3Dn
+GpHVTH1hCWsKRhQjxuOOq/X21YpvgJ2IewQAFggAIwUCV2pM1BwccGF0cmljZS5s
+dW11bWJhQGV4YW1wbGUubmV0AAoJEBOVY2gqAg0KPJMA/0+3s4HPotwYw8K8pug3
+7Mxgd9LNIBi/d0nSpBnZTHySAQDURAoIZp0IZI/PS7Jc9A8M3TgWdm1LUkj+qU9x
+3L6RCQ==
+=3oWb
+-----END PGP SIGNATURE-----
diff --git a/tests/openpgp/samplemsgs/sig-2-keys-2.sig b/tests/openpgp/samplemsgs/sig-2-keys-2.sig
new file mode 100644 (file)
index 0000000..187e22a
Binary files /dev/null and b/tests/openpgp/samplemsgs/sig-2-keys-2.sig differ
diff --git a/tests/openpgp/samplemsgs/signed-1-key-1.asc b/tests/openpgp/samplemsgs/signed-1-key-1.asc
new file mode 100644 (file)
index 0000000..d71c74d
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+owGbwMvMwMG4yvnjneP/Lm5nPJ2exBCe5XbZI7E8O7UyVb1YwTk/LzmntDgzP8+K
+i9OzBCiSl1+ikJpYXKlQkq9QkJMIpDNSFZJz8svzFMozUvMUKvNL1ctSFdKByoAq
+ikrzwArKM/JzUrk4kzOLkkuL9bg6GU1YGBg5GORYmUD2icsUl6SWpeolZWbnO6RW
+JOYW5KTq5aWWMHBxCsAcl9zJ/od/6lrXa9snvZR9wrpXuEblNq/F3pzYWed8DZd8
+aApUzgkTy1K64+QU7HuL525G4vM3Yibfvq+VLTf/aFx46FSc7I2MpE2vElhvztZ5
+8SQ2ZWe7m5apT9qu7UfXyhrxxfutyt+ot3daXp3hyxuVPzdfKD147N8djoc5634y
+6n9Uvfa7Uec030zZjae3VHScMDY1tD7yQjrFNnXptYQXP+RPtD1l+Kn33I87jeHT
+SYnUk8r3zD71zahJbfZYwem0c+WbOzs/+qQeKeE/kaL+Y8GHeY9vbkq6eGNKWag+
+Y+Ydhac6bccZHEpXHFBfy3iBJ9OrZub93Oulx4Tnz5U5tZuL31VZOSzlyESvoJeb
+/0kDAA==
+=T94L
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/signed-1-key-1.gpg b/tests/openpgp/samplemsgs/signed-1-key-1.gpg
new file mode 100644 (file)
index 0000000..8ab90c1
--- /dev/null
@@ -0,0 +1,6 @@
\ 15RkhTG\14Þ´\91ì½¢ø£â¶]ä¨\ 5\ 4LÖÇF\ 5_1I£\98õA|\14döîlîdïάwæîfUÄZTÔ¶T#Z\11\ 4\vm}\82 ¢±?DÉ[b\12Úþð\81\96ÈBµ>óCDÑöÌ.þ\9b9ç;çûÎwÎ\8fã>öùKN/yy¯çýðå\92\9b\8fb¾æÖº£kl
\88TT*XJ\13\94(hà°Ä¦R\9a\86NÆX\vp\92¢\90\10.x\12\18\a\85á¬p\9d8\88\ 4X\1a
+LB\1d\8b\11/\1e\ 2\ 2Ë\Ê-»\981Sº¹[i\1aض\89¸\b\8c{.ã-03R\15\ 6Ý\89H\88!/å@\12\b\ 5Á\9d\1c²y.¤D\86b2\aÄ\!¸d\14cËÉ\16âÆ+\ 1êI:Í
+H\17ÒB\930\95\v\15Ä\15ë\88KÁ¥\96pã4\ e\84ÇA
+³¨\96re{\92¡2      )\92+ ¸T®g)¬g:ØÂY\82Y\b\ 4K8\ eIKúarK¤\90R\998;~\19êÍr°E\8aJ\1c²¨®8\93C¬d\81·è\fdm¦h\8di̬\81¦\8ah8\ 4\8dª¢qqµiTÕèg´*\84ñÆ°iT# ­©\98W³L#¬\v\1aWU\17#³M£YwÒì\1c¥KÖÂ%\9a\86Oâ°-ÚZeã\1a       $XBÙ\ 53p]\1e®\8bñ\8cp2Ô¤\fk7º\b\89bßYzS(\15}Ôó9\ 2\1dÂá´\ f\9b=J9\8eeTTÀjEÓ\9a±\8994\ 4Sõm,\16"©¡õÔ\15ÌÂ;b\8e\87\82¦\9a{KÂ¥¾\12¿oò\98\8fô\91M
+âz2´2Æ\92b!m#©´C+9U>Ó\98ðá"_u\94½\9fs²®kÆ'_¶æË\97?þë»îÞO\8däËYÚ;\14\1dÛ|;¢v~\9b\7fÚ9ÅÿOà«k\rÑw\8b>o\8fÔ¶ö?\ÙÑÚð}Ç\ f\v\1a\86w\ f\ 4º³\7fdÚK\83\7f\7f3ÿÜ\9f]÷Ç®\9a¶oý/½³g\1c=\16¼bø\ 3wwN¸øk\7fUòFp(\96º:r!\94T\13çÞ+«í\19_¿`Ü\89½¥Ùg«§\8f\f¿ú÷ìù\9aÏvµ\aúúzïøï\ eÖv®-\1f\1cý:\90\8f>\fÍÛ|áÔ\81×ûGWÚµ_<Øtý~ä@¤ûÐ\9e\9fÖmÌ\rö\fT\1f\f¾¹óøö5údëÏÁ\9b;^È[ûGÙñmyþÎ:Tî&ÊþûíÅ\8a\rCÆë[ÎÜ\85Ýj{Û\99\911*ÿ\96_\7fÞuîÈ%1òû£ÿ\ 1
\ No newline at end of file
diff --git a/tests/openpgp/samplemsgs/signed-1-key-2.asc b/tests/openpgp/samplemsgs/signed-1-key-2.asc
new file mode 100644 (file)
index 0000000..64483fb
--- /dev/null
@@ -0,0 +1,12 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+owGbwMvMwCEmPDU5Q4uJl4vx9AG9JIbwLLcnnCHl+Qq5qXkKOfn52akpCvmlJQpp
+Rfm5CiUZqQoFRZnF+XkKSYlFxTpcnP55qQrFieUKuaUpurpcnCFABflAVUVgweIS
+oCI9Li6//HKFnNQSoJEK6UCqJCOzWKEoMz2jxEqhBGgTxMTUomKFxKJUsJ2Zeelg
+S0H2lWfmpeSX63GFZ2TmAA0H2pefBpLIVShPLIarTixRSMzJAWsAOkVBVxfMhDgF
+pCc9v0QhI7OEKzMPLJGRmpiix9VRzcIgxsGgzMoE8rWMTEFiSVFmcqpeTmluaW5S
+okNqRWJuQU6qXl5qCQMXpwAsoD78YWRY1rZ/7kOLr4GrbvSU6HqKnVy6+1BllLYd
+c5ebbu2ltZ89GRkOBN6327Z+J4eaa5ppOGeA08P8xgvlcft8tz5u9i7jncwKAA==
+=uuW/
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/signed-1-key-2.gpg b/tests/openpgp/samplemsgs/signed-1-key-2.gpg
new file mode 100644 (file)
index 0000000..23f0457
Binary files /dev/null and b/tests/openpgp/samplemsgs/signed-1-key-2.gpg differ
diff --git a/tests/openpgp/samplemsgs/signed-2-keys-1.asc b/tests/openpgp/samplemsgs/signed-2-keys-1.asc
new file mode 100644 (file)
index 0000000..38d25b1
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+owGbwMvMwMG4yvnjneP/Lm5nmADiiglPTc7QYuLlYjwdm8QQnuVu45iTo+CWmZeY
+npOq4JNYXqyQm1ipkJSqkFRZkFhcnJoCZCjkpCYW5WXmpSuUZKQqFGfmFgDVJhaV
+KOSnKaTkA8W5yjNLMvJLS4DymXnZQAE9ro5qFgYxDgZlViaQJTIyBYklRZnJqXo5
+pbmluUmJDqkViSBj9PJSSxi4OAVgzpoVw/A/fBVnTGzGFd0DUzZcu6HNcm/6mpaZ
+CeuOc+89eOsmg9YGRYb/5U3LTx4pf5Ru3ceW/X+Vkdq22kuGCxqaVwYJHZSL/xfN
+08lowsLAyMEgB7FdXKa4JLUsVS8pMzsf3WJY8LR2sv/P9VLy+VZyrvhebd6WMyoz
+V/kIXW+p2WbcI1vw58xdofBbU9eHtM2Y47ft6Bm5bS0NL6d6zzl7YsfLl5qKLFJb
+s/cVKFe1MM7POqrEqzEr7cqe3amsN08ntDsvbLr3tc1ATKhTgMVKMIhjznseR54F
+L1tyl7eUv96SYCbIf+uzu5vZnjWHvulP1zm579qel7afa77Enc94Nnn+U4Xf7F8W
+PA5Kumj01S639ux3PcYFLR9+tey0bTDyNPhkqiddvLY9O8ztd94SDw4ph4+bbol+
+5S1+5dJ1vl1w7VSbtSf5dPfV1uxLr7UQnvGiwplnVpzt8XOvFXbHZ6yx2Hm52Kry
+0TndFZfZqkRzFGxn7bkOAA==
+=iswv
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/signed-2-keys-1.gpg b/tests/openpgp/samplemsgs/signed-2-keys-1.gpg
new file mode 100644 (file)
index 0000000..ebf6771
Binary files /dev/null and b/tests/openpgp/samplemsgs/signed-2-keys-1.gpg differ
diff --git a/tests/openpgp/samplemsgs/signed-2-keys-2.asc b/tests/openpgp/samplemsgs/signed-2-keys-2.asc
new file mode 100644 (file)
index 0000000..5219e13
--- /dev/null
@@ -0,0 +1,24 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+owFdk21sFFUUhqcf4O7wIQQLpi71skoKZFj4wUdrgiwYxVaUFrZUvkzuzJ7ZuezM
+3M3Mnd2OEpNiTVGTQlSKUn+A1WjBBFMDRIWAKG0qJYEWhVKgkECqBkrQ8AM1u96Z
+hVT9NTmZc573ve+5d8eEIiEwdcpORZtTOEEUdnhlwb5n7lzqzp49XHDqV1mo37xi
+ZTC8jjrIAGxKiKjI5QXWdZpBTANkYJuBhRhFMiDHVEia6JJXMgsw85pFbLqI6nGU
+wS7iEzpJgi0hbMa9NmLaju73WShOEiZhruSBTeTDXRQHMHyMSpg3oAG2kEZslCaQ
+QVTlzcRM2EvDYjBc6xAGvi2FmszClhtByDfv2IyTVOCivhQxGSQsXwzbtmNwhOgd
+TMNpGP3p6eWnOGe549v8D4tbMqmsc4pJGZJdkRiEYcZpvkWaMZEXlAycS6jFKVX3
+A7QAJcBkOqCMBrzgnvmARZ2EJolktClFde9M/27iKVOHaaMxZYiuIwsUyuN7FfKj
+tpiijAsQvioXZajFNDcvzwfiFGzP8SiC+DXC9/fJU1H5J+YtWhJxPjV/HSqAjlQL
+wMsmSZSkf1CeYYQvIDh3LopRA62msswXK6FwNWGcIzsJVAOW6hgQFt8qWFAsFASE
+sjGF3u2aFuKCaYjIJEmj0ICNlA4RE5ggBic9uIpd6kPZyjdLVjSdbP+96b2J2rhc
+6bKGZXtvnJv+1L7wY4MZdSC06tOxx74KzS7rosOTWn6MbN8wPHT1txnNVwJjRnpz
+j7wxs7uxV5+8dsPWRzsbetK3bx0emD0wuWfhJ92pNT8fbNh1oO5O1clXbo9r6u96
+ePDQ3ujiwc9PPP3n+x+t7r320xKnONu3deXGlmhh4+nhDyraXv871ifYtUvGt7Wd
+jw0PdexeVDLyS1Wd3tizqXx/y/XpFaj1h7e3dLofJ7+YX8NK9xRFrweaZ/4hvTy2
+dekL+w+tiu3JFlX2GJ+VH6m7cXHdc3drl3//+MXO6tx3E53si32nDo7ULO5o73qp
+XbnUG2xtP13XX7roKB3Z9lqxMDUgPJFPLRRKYWYRBSK6YziGjP8f3YNHXV4v5BTt
+5qbStev/6ghX7xz/4e4jQ09Wtm5898Ss4LfbmkswuyDkttyc9807ZRfmfX3m+Vv1
+/bO+HIzB9sv3pGjwzHGlv+JZ8R8=
+=pstx
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/samplemsgs/signed-2-keys-2.gpg b/tests/openpgp/samplemsgs/signed-2-keys-2.gpg
new file mode 100644 (file)
index 0000000..42741b3
Binary files /dev/null and b/tests/openpgp/samplemsgs/signed-2-keys-2.gpg differ
diff --git a/tests/openpgp/samplemsgs/signed-data-1.txt b/tests/openpgp/samplemsgs/signed-data-1.txt
new file mode 100644 (file)
index 0000000..0607201
--- /dev/null
@@ -0,0 +1,7 @@
+This conjunction of an immense military establishment and a large arms
+industry is now in the American experience... We must not fail to
+comprehend its grave implications... We must guard against the
+acquisition of unwarranted influence...by the military-industrial
+complex.  The potential for the disastrous rise of misplaced power
+exists and will persist.
+               -- Dwight D. Eisenhower, from his farewell address in 1961
diff --git a/tests/openpgp/samplemsgs/signedz0-1-key-1.gpg b/tests/openpgp/samplemsgs/signedz0-1-key-1.gpg
new file mode 100644 (file)
index 0000000..400bcba
Binary files /dev/null and b/tests/openpgp/samplemsgs/signedz0-1-key-1.gpg differ
diff --git a/tests/openpgp/samplemsgs/signedz0-1-key-2.gpg b/tests/openpgp/samplemsgs/signedz0-1-key-2.gpg
new file mode 100644 (file)
index 0000000..55f3637
Binary files /dev/null and b/tests/openpgp/samplemsgs/signedz0-1-key-2.gpg differ
diff --git a/tests/openpgp/samplemsgs/signedz0-2-keys-1.gpg b/tests/openpgp/samplemsgs/signedz0-2-keys-1.gpg
new file mode 100644 (file)
index 0000000..84f2fd2
Binary files /dev/null and b/tests/openpgp/samplemsgs/signedz0-2-keys-1.gpg differ
diff --git a/tests/openpgp/samplemsgs/signedz0-2-keys-2.gpg b/tests/openpgp/samplemsgs/signedz0-2-keys-2.gpg
new file mode 100644 (file)
index 0000000..7e142b9
Binary files /dev/null and b/tests/openpgp/samplemsgs/signedz0-2-keys-2.gpg differ
diff --git a/tests/openpgp/seat.scm b/tests/openpgp/seat.scm
new file mode 100755 (executable)
index 0000000..aceecca
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking encryption, signing, and producing armored output"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg usrpass1 '(--yes -seat -r two@example.com --passphrase-fd "0"))
+    (tr:gpg "" '(--yes))
+    (tr:assert-weak-identity source)))
+ plain-files)
diff --git a/tests/openpgp/setup.scm b/tests/openpgp/setup.scm
new file mode 100755 (executable)
index 0000000..9ad19c2
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(echo "Creating test environment...")
+
+(letfd ((fd (open "random_seed" (logior O_WRONLY O_CREAT O_BINARY) #o600)))
+  (call-with-fds (list (tool 'mktdata) "600") CLOSED_FD fd STDERR_FILENO))
+
+(for-each-p
+ "Creating configuration files"
+ (lambda (name)
+   (file-copy (in-srcdir (string-append name ".tmpl")) name)
+   (let ((p (open-input-output-file name)))
+     (cond
+      ((string=? "gpg.conf" name)
+       (if have-opt-always-trust
+          (display "no-auto-check-trustdb\n" p))
+       (display (string-append "agent-program "
+                              (tool 'gpg-agent)
+                              "|--debug-quick-random\n") p)
+       (display "allow-weak-digest-algos\n" p))
+      ((string=? "gpg-agent.conf" name)
+       (display (string-append "pinentry-program " PINENTRY "\n") p)))))
+ '("gpg.conf" "gpg-agent.conf"))
+
+(echo "Starting gpg-agent...")
+(call-check `(,(tool 'gpg-connect-agent) --verbose
+             ,(string-append "--agent-program=" (tool 'gpg-agent)
+                             "|--debug-quick-random")
+             /bye))
+
+(for-each-p "Creating sample data files"
+  (lambda (size)
+    (letfd ((fd (open (string-append "data-" (number->string size))
+                     (logior O_WRONLY O_CREAT O_BINARY) #o600)))
+      (call-with-fds (list (tool 'mktdata) (number->string size))
+                    CLOSED_FD fd STDERR_FILENO)))
+  '(500 9000 32000 80000))
+
+(define (dearmor source-name sink-name)
+  (pipe:do
+   (pipe:open source-name (logior O_RDONLY O_BINARY))
+   (pipe:spawn `(,@GPG --dearmor))
+   (pipe:write-to sink-name
+                 (logior O_WRONLY O_CREAT O_BINARY)
+                 #o600)))
+
+(for-each-p "Unpacking samples"
+  (lambda (name)
+    (dearmor (in-srcdir (string-append name "o.asc")) name))
+  '("plain-1" "plain-2" "plain-3" "plain-large"))
+
+;; XXX implement cleanup
+(catch '()
+       (mkdir "private-keys-v1.d" "-rwx"))
+
+(define counter (make-counter))
+(for-each-p' "Storing private keys"
+  (lambda (name)
+    (dearmor (in-srcdir (string-append "/privkeys/" name ".asc"))
+            (string-append "private-keys-v1.d/" name ".key")))
+  (lambda (name) (counter))
+  '("50B2D4FA4122C212611048BC5FC31BD44393626E"
+    "7E201E28B6FEB2927B321F443205F4724EBE637E"
+    "13FDB8809B17C5547779F9D205C45F47CE0217CE"
+    "343D8AF79796EE107D645A2787A9D9252F924E6F"
+    "8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34"
+    "0D6F6AD4C4C803B25470F9104E9F4E6A4CA64255"
+    "FD692BD59D6640A84C8422573D469F84F3B98E53"
+    "76F7E2B35832976B50A27A282D9B87E44577EB66"
+    "A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD"
+    "00FE67F28A52A8AA08FFAED20AF832DA916D1985"
+    "1DF48228FEFF3EC2481B106E0ACA8C465C662CC5"
+    "A2832820DC9F40751BDCD375BB0945BA33EC6B4C"
+    "ADE710D74409777B7729A7653373D820F67892E0"
+    "CEFC51AF91F68A2904FBFF62C4F075A4785B803F"
+    "1E28F20E41B54C2D1234D896096495FF57E08D18"
+    "EB33B687EB8581AB64D04852A54453E85F3DF62D"
+    "C6A6390E9388CDBAD71EAEA698233FE5E04F001E"
+    "D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3"))
+
+(info "Importing public demo and test keys")
+(call-check `(,@GPG --yes --import
+                   ,(in-srcdir "pubdemo.asc")
+                   ,(in-srcdir "pubring.asc")
+                    ,(in-srcdir key-file1)))
+;; (letfd ((source (open (in-srcdir "pubring.pkr.asc") O_RDONLY)))
+;;        ((gpg-pipe '(--dearmor) '(--yes --import) STDERR_FILENO)
+;;     source CLOSED_FD))
+(pipe:do
+ (pipe:open (in-srcdir "pubring.pkr.asc") (logior O_RDONLY O_BINARY))
+ (pipe:spawn `(,@GPG --dearmor))
+ (pipe:spawn `(,@GPG --yes --import)))
+
+(info "Preset passphrases")
+;; one@example.com
+(call-check `(,(tool 'gpg-preset-passphrase)
+             --preset --passphrase def
+             "50B2D4FA4122C212611048BC5FC31BD44393626E"))
+(call-check `(,(tool 'gpg-preset-passphrase)
+             --preset --passphrase def
+             "7E201E28B6FEB2927B321F443205F4724EBE637E"))
+;; alpha@example.net
+(call-check `(,(tool 'gpg-preset-passphrase)
+             --preset --passphrase abc
+             "76F7E2B35832976B50A27A282D9B87E44577EB66"))
+(call-check `(,(tool 'gpg-preset-passphrase)
+             --preset --passphrase abc
+             "A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD"))
+
+(echo "All set up.")
diff --git a/tests/openpgp/signencrypt-dsa.scm b/tests/openpgp/signencrypt-dsa.scm
new file mode 100755 (executable)
index 0000000..baf1def
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking signing and encryption using DSA"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg usrpass1 `(--yes --passphrase-fd "0" -se
+                            -u ,dsa-usrname1
+                            --recipient ,dsa-usrname2))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
+
+(define algos (if (have-hash-algo? "RIPEMD160")
+                 '("SHA1" "RIPEMD160")
+                 '("SHA1")))
+(for-each-p
+ "Checking signing and encryption using DSA with a specific hash algorithm"
+ (lambda (hash)
+   (tr:do
+    (tr:open (car plain-files))
+    (tr:gpg usrpass1 `(--yes --passphrase-fd "0" -se
+                            -u ,dsa-usrname1
+                            --recipient ,dsa-usrname2
+                            --digest-algo ,hash))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity (car plain-files))))
+ algos)
diff --git a/tests/openpgp/signencrypt.scm b/tests/openpgp/signencrypt.scm
new file mode 100755 (executable)
index 0000000..b138dce
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking signing and encryption"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg usrpass1 `(--yes --passphrase-fd "0" -se --recipient ,usrname2))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
+
+(info "Checking bug 537: MDC problem with old style compressed packets.")
+(lettmp (tmp)
+  (call-popen `(,@GPG --yes --passphrase-fd "0"
+                     --output ,tmp ,(in-srcdir "bug537-test.data.asc"))
+             usrpass1)
+  (if (not (string=? "4336AE2A528FAE091E73E59E325B588FEE795F9B"
+                    (cadar (gpg-hash-string `(--print-md SHA1 ,tmp) ""))))
+      (error "bug537-test.data.asc: mismatch (bug 537)")))
diff --git a/tests/openpgp/sigs-dsa.scm b/tests/openpgp/sigs-dsa.scm
new file mode 100755 (executable)
index 0000000..bf5e415
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking signing using DSA with the default hash algorithm"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg "" `(--yes --sign --user ,dsa-usrname1))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
+
+(define algos (if (have-hash-algo? "RIPEMD160")
+                 '("SHA1" "RIPEMD160")
+                 '("SHA1")))
+(for-each-p
+ "Checking signing using DSA with a specific hash algorithm"
+ (lambda (hash)
+   (tr:do
+    (tr:open (car plain-files))
+    (tr:gpg "" `(--yes --sign --user ,dsa-usrname1 --digest-algo ,hash))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity (car plain-files))))
+ algos)
diff --git a/tests/openpgp/sigs.scm b/tests/openpgp/sigs.scm
new file mode 100755 (executable)
index 0000000..c478231
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(for-each-p
+ "Checking signing with the default hash algorithm"
+ (lambda (source)
+   (tr:do
+    (tr:open source)
+    (tr:gpg "" '(--yes --sign))
+    (tr:gpg "" '(--yes))
+    (tr:assert-identity source)))
+ (append plain-files data-files))
+
+(for-each-p
+ "Checking signing with a specific hash algorithm"
+ (lambda (hash)
+   (if (have-pubkey-algo? "RSA")
+       ;; RSA key, so any hash is okay.
+       (tr:do
+       (tr:open (car plain-files))
+       (tr:gpg "" `(--yes --sign --user ,usrname3 --digest-algo ,hash))
+       (tr:gpg "" '(--yes))
+       (tr:assert-identity (car plain-files))))
+   (if (not (equal? "MD5" hash))
+       ;; Using the DSA sig key - only 160 bit or larger hashes
+       (tr:do
+       (tr:open (car plain-files))
+       (tr:gpg usrpass1
+               `(--yes --sign --passphrase-fd "0" --digest-algo ,hash))
+       (tr:gpg "" '(--yes))
+       (tr:assert-identity (car plain-files)))))
+ all-hash-algos)
diff --git a/tests/openpgp/tofu.scm b/tests/openpgp/tofu.scm
new file mode 100755 (executable)
index 0000000..38b6a0f
--- /dev/null
@@ -0,0 +1,167 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+ ;; Redefine GPG without --always-trust and a fixed time.
+(define GPG `(,(tool 'gpg) --no-permission-warning
+             --faked-system-time=1466684990))
+(define GNUPGHOME (getenv "GNUPGHOME"))
+(if (string=? "" GNUPGHOME)
+    (error "GNUPGHOME not set"))
+
+(catch (skip "Tofu not supported")
+       (call-check `(,@GPG --trust-model=tofu --list-config)))
+
+(define KEYS '("2183839A" "BC15C85A" "EE37CF96"))
+
+;; Import the test keys.
+(call-check `(,@GPG --import ,(in-srcdir "tofu-keys.asc")))
+
+;; Make sure the keys are imported.
+(for-each (lambda (keyid)
+           (catch (error "Missing key" keyid)
+                  (call-check `(,@GPG --list-keys ,keyid))))
+         KEYS)
+
+;; Get tofu policy for KEYID.  Any remaining arguments are simply
+;; passed to GPG.
+;;
+;; This function only supports keys with a single user id.
+(define (getpolicy keyid format . args)
+  (let ((policy
+        (list-ref (assoc "uid" (gpg-with-colons
+                                `(--tofu-db-format ,format
+                                  --trust-model=tofu
+                                  ,@args
+                                  --list-keys ,keyid))) 17)))
+    (unless (member policy '("auto" "good" "unknown" "bad" "ask"))
+           (error "Bad policy:" policy))
+    policy))
+
+;; Check that KEYID's tofu policy matches EXPECTED-POLICY.  Any
+;; remaining arguments are simply passed to GPG.
+;;
+;; This function only supports keys with a single user id.
+(define (checkpolicy keyid format expected-policy . args)
+  (let ((policy (apply getpolicy `(,keyid ,format ,@args))))
+    (unless (string=? policy expected-policy)
+           (error keyid ": Expected policy to be" expected-policy
+                  "but got" policy))))
+
+;; Get the trust level for KEYID.  Any remaining arguments are simply
+;; passed to GPG.
+;;
+;; This function only supports keys with a single user id.
+(define (gettrust keyid format . args)
+  (let ((trust
+        (list-ref (assoc "pub" (gpg-with-colons
+                                `(--tofu-db-format ,format
+                                  --trust-model=tofu
+                                  ,@args
+                                  --list-keys ,keyid))) 1)))
+    (unless (and (= 1 (string-length trust))
+                (member (string-ref trust 0) (string->list "oidreqnmfuws-")))
+           (error "Bad trust value:" trust))
+    trust))
+
+;; Check that KEYID's trust level matches EXPECTED-TRUST.  Any
+;; remaining arguments are simply passed to GPG.
+;;
+;; This function only supports keys with a single user id.
+(define (checktrust keyid format expected-trust . args)
+  (let ((trust (apply gettrust `(,keyid ,format ,@args))))
+    (unless (string=? trust expected-trust)
+           (error keyid ": Expected trust to be" expected-trust
+                  "but got" trust))))
+
+;; Set key KEYID's policy to POLICY.  Any remaining arguments are
+;; passed as options to gpg.
+(define (setpolicy keyid format policy . args)
+  (call-check `(,@GPG --tofu-db-format ,format
+                     --trust-model=tofu ,@args
+                     --tofu-policy ,policy ,keyid)))
+
+(for-each-p
+ "Testing tofu db formats"
+ (lambda (format)
+   ;; Carefully remove the TOFU db.
+   (catch '() (unlink (string-append GNUPGHOME "/tofu.db")))
+   (catch '() (unlink-recursively (string-append GNUPGHOME "/tofu.d")))
+
+   ;; Verify a message.  There should be no conflict and the trust
+   ;; policy should be set to auto.
+   (call-check `(,@GPG --tofu-db-format ,format --trust-model=tofu
+                      --verify ,(in-srcdir "tofu-2183839A-1.txt")))
+
+   (checkpolicy "2183839A" format "auto")
+   ;; Check default trust.
+   (checktrust "2183839A" format "m")
+
+   ;; Trust should be derived lazily.  Thus, if the policy is set to
+   ;; auto and we change --tofu-default-policy, then the trust should
+   ;; change as well.  Try it.
+   (checktrust "2183839A" format "f" '--tofu-default-policy=good)
+   (checktrust "2183839A" format "-" '--tofu-default-policy=unknown)
+   (checktrust "2183839A" format "n" '--tofu-default-policy=bad)
+
+   ;; Change the policy to something other than auto and make sure the
+   ;; policy and the trust are correct.
+   (for-each-p
+    ""
+    (lambda (policy)
+      (let ((expected-trust
+            (cond
+             ((string=? "good" policy) "f")
+             ((string=? "unknown" policy) "-")
+             (else "n"))))
+       (setpolicy "2183839A" format policy)
+
+       ;; Since we have a fixed policy, the trust level shouldn't
+       ;; change if we change the default policy.
+       (for-each-p
+        ""
+        (lambda (default-policy)
+          (checkpolicy "2183839A" format policy
+                       '--tofu-default-policy default-policy)
+          (checktrust "2183839A" format expected-trust
+                      '--tofu-default-policy default-policy))
+        '("auto" "good" "unknown" "bad" "ask"))))
+    '("good" "unknown" "bad"))
+
+   ;; BC15C85A conflicts with 2183839A.  On conflict, this will set
+   ;; BC15C85A to ask.  If 2183839A is auto (it's not, it's bad), then
+   ;; it will be set to ask.
+   (call-check `(,@GPG --tofu-db-format ,format --trust-model=tofu
+                      --verify ,(in-srcdir "tofu-BC15C85A-1.txt")))
+   (checkpolicy "BC15C85A" format "ask")
+   (checkpolicy "2183839A" format "bad")
+
+   ;; EE37CF96 conflicts with 2183839A and BC15C85A.  We change
+   ;; BC15C85A's policy to auto and leave 2183839A's policy at bad.
+   ;; This conflict should cause BC15C85A's policy to be changed to
+   ;; ask (since it is auto), but not affect 2183839A's policy.
+   (setpolicy "BC15C85A" format "auto")
+   (checkpolicy "BC15C85A" format "auto")
+   (call-check `(,@GPG --tofu-db-format ,format --trust-model=tofu
+                      --verify ,(in-srcdir "tofu-EE37CF96-1.txt")))
+   (checkpolicy "BC15C85A" format "ask")
+   (checkpolicy "2183839A" format "bad")
+   (checkpolicy "EE37CF96" format "ask"))
+ '("split" "flat"))
index 18c1756..0d34af4 100755 (executable)
@@ -4,6 +4,9 @@
 
 # set -x
 
+# Redefine GPG with a fixed time.
+GPG="$GPG --faked-system-time=1466684990"
+
 KEYS="2183839A BC15C85A EE37CF96"
 
 # Make sure $srcdir is set.
diff --git a/tests/openpgp/use-exact-key.scm b/tests/openpgp/use-exact-key.scm
new file mode 100755 (executable)
index 0000000..bec537b
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+;; Import the sample key
+;;
+;; pub   1024R/8BC90111 2015-12-02
+;;       Key fingerprint = E657 FB60 7BB4 F21C 90BB  6651 BC06 7AF2 8BC9 0111
+;; uid       [ultimate] Barrett Brown <barrett@example.org>
+;; sub   1024R/3E880CFF 2015-12-02 (encryption)
+;; sub   1024R/F5F77B83 2015-12-02 (signing)
+;; sub   1024R/45117079 2015-12-02 (encryption)
+;; sub   1024R/1EA97479 2015-12-02 (signing)
+
+(info "Importing public key.")
+(call-check
+ `(,(tool 'gpg) --import
+   ,(in-srcdir "samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc")))
+
+;; By default, the most recent, valid signing subkey (1EA97479).
+(for-each-p
+ "Checking that the most recent, valid signing subkey is used by default"
+ (lambda (keyid)
+   (tr:do
+     (tr:pipe-do
+      (pipe:defer (lambda (sink) (display "" (fdopen sink "w"))))
+      (pipe:gpg `(-s -u ,keyid))
+      (pipe:gpg '(--verify --status-fd=1)))
+     (tr:call-with-content
+      (lambda (c)
+       (unless (string-contains?
+                c "VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479")
+           (exit 1))))))
+ '("8BC90111" "3E880CFF" "F5F77B83" "45117079" "1EA97479"))
+
+;; But, if we request a particular signing key, we should get it.
+(for-each-p
+ "Checking that we can select a specific signing key"
+ (lambda (keyid)
+   (tr:do
+     (tr:pipe-do
+      (pipe:defer (lambda (sink) (display "" (fdopen sink "w"))))
+      (pipe:gpg `(-s -u ,(string-append keyid "!")))
+      (pipe:gpg '(--verify --status-fd=1)))
+     (tr:call-with-content
+      (lambda (c)
+       ;; XXX we do not have a regexp library
+       (unless (and (string-contains? c "VALIDSIG")
+                    (string-contains? c keyid))
+           (exit 1))))))
+ '("8BC90111" "F5F77B83" "1EA97479"))
diff --git a/tests/openpgp/verify.scm b/tests/openpgp/verify.scm
new file mode 100755 (executable)
index 0000000..de03db5
--- /dev/null
@@ -0,0 +1,274 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+;;
+;; Two simple tests to check that verify fails for bad input data
+;;
+(for-each-p
+ "Checking bogus signature"
+ (lambda (char)
+   (lettmp (x)
+     (pipe:do
+      (pipe:spawn `(,(tool 'mktdata) --char ,char "64"))
+      (pipe:write-to x (logior O_WRONLY O_CREAT O_BINARY) #o600))
+     (if (= 0 (call `(,@GPG --verify ,x data-500)))
+        (error "no error code from verify"))))
+ '("0x2d" "0xca"))
+
+;; A plain signed message created using
+;;  echo abc | gpg --homedir . --passphrase-fd 0 -u Alpha -z0 -sa msg
+(define msg_ols_asc "
+-----BEGIN PGP MESSAGE-----
+
+kA0DAAIRLXJ8x2hpdzQBrQEHYgNtc2dEDFJaSSB0aGluayB0aGF0IGFsbCByaWdo
+dC10aGlua2luZyBwZW9wbGUgaW4gdGhpcyBjb3VudHJ5IGFyZSBzaWNrIGFuZAp0
+aXJlZCBvZiBiZWluZyB0b2xkIHRoYXQgb3JkaW5hcnkgZGVjZW50IHBlb3BsZSBh
+cmUgZmVkIHVwIGluIHRoaXMKY291bnRyeSB3aXRoIGJlaW5nIHNpY2sgYW5kIHRp
+cmVkLiAgSSdtIGNlcnRhaW5seSBub3QuICBCdXQgSSdtCnNpY2sgYW5kIHRpcmVk
+IG9mIGJlaW5nIHRvbGQgdGhhdCBJIGFtLgotIE1vbnR5IFB5dGhvbgqIPwMFAEQM
+UlotcnzHaGl3NBECR4IAoJlEGTY+bHjD2HYuCixLQCmk01pbAKCIjkzLOAmkZNm0
+D8luT78c/1x45Q==
+=a29i
+-----END PGP MESSAGE-----
+")
+
+;; A plain signed message created using
+;;  echo abc | gpg --homedir . --passphrase-fd 0 -u Alpha -sa msg
+(define msg_cols_asc "
+-----BEGIN PGP MESSAGE-----
+
+owGbwMvMwCSoW1RzPCOz3IRxLSN7EnNucboLT6Cgp0JJRmZeNpBMLFFIzMlRKMpM
+zyjRBQtm5qUrFKTmF+SkKmTmgdQVKyTnl+aVFFUqJBalKhRnJmcrJOalcJVkFqWm
+KOSnKSSlgrSU5OekQMzLL0rJzEsEKk9JTU7NK4EZBtKcBtRRWgAzlwtmbnlmSQbU
+GJjxCmDj9RQUPNVzFZJTi0oSM/NyKhXy8kuAYk6lJSBxLlTF2NziqZCYq8elq+Cb
+n1dSqRBQWZKRn8fVYc/MygAKBljYCDIFiTDMT+9seu836Q+bevyHTJ0dzPNuvCjn
+ZpgrwX38z58rJsfYDhwOSS4SkN/d6vUAAA==
+=s6sY
+-----END PGP MESSAGE-----
+")
+
+;; A PGP 2 style message.
+(define msg_sl_asc "
+-----BEGIN PGP MESSAGE-----
+
+iD8DBQBEDFJaLXJ8x2hpdzQRAkeCAKCZRBk2Pmx4w9h2LgosS0AppNNaWwCgiI5M
+yzgJpGTZtA/Jbk+/HP9ceOWtAQdiA21zZ0QMUlpJIHRoaW5rIHRoYXQgYWxsIHJp
+Z2h0LXRoaW5raW5nIHBlb3BsZSBpbiB0aGlzIGNvdW50cnkgYXJlIHNpY2sgYW5k
+CnRpcmVkIG9mIGJlaW5nIHRvbGQgdGhhdCBvcmRpbmFyeSBkZWNlbnQgcGVvcGxl
+IGFyZSBmZWQgdXAgaW4gdGhpcwpjb3VudHJ5IHdpdGggYmVpbmcgc2ljayBhbmQg
+dGlyZWQuICBJJ20gY2VydGFpbmx5IG5vdC4gIEJ1dCBJJ20Kc2ljayBhbmQgdGly
+ZWQgb2YgYmVpbmcgdG9sZCB0aGF0IEkgYW0uCi0gTW9udHkgUHl0aG9uCg==
+=0ukK
+-----END PGP MESSAGE-----
+")
+
+;; An OpenPGP message lacking the onepass packet.  We used to accept
+;; such messages but now consider them invalid.
+(define bad_ls_asc "
+-----BEGIN PGP MESSAGE-----
+
+rQEHYgNtc2dEDFJaSSB0aGluayB0aGF0IGFsbCByaWdodC10aGlua2luZyBwZW9w
+bGUgaW4gdGhpcyBjb3VudHJ5IGFyZSBzaWNrIGFuZAp0aXJlZCBvZiBiZWluZyB0
+b2xkIHRoYXQgb3JkaW5hcnkgZGVjZW50IHBlb3BsZSBhcmUgZmVkIHVwIGluIHRo
+aXMKY291bnRyeSB3aXRoIGJlaW5nIHNpY2sgYW5kIHRpcmVkLiAgSSdtIGNlcnRh
+aW5seSBub3QuICBCdXQgSSdtCnNpY2sgYW5kIHRpcmVkIG9mIGJlaW5nIHRvbGQg
+dGhhdCBJIGFtLgotIE1vbnR5IFB5dGhvbgqIPwMFAEQMUlotcnzHaGl3NBECR4IA
+oJlEGTY+bHjD2HYuCixLQCmk01pbAKCIjkzLOAmkZNm0D8luT78c/1x45Q==
+=Mpiu
+-----END PGP MESSAGE-----
+")
+
+
+;; A signed message prefixed with an unsigned literal packet.
+;; (fols = faked-literal-data, one-pass, literal-data, signature)
+;; This should throw an error because running gpg to extract the
+;; signed data will return both literal data packets
+(define bad_fols_asc "
+-----BEGIN PGP MESSAGE-----
+
+rF1iDG1zZy51bnNpZ25lZEQMY0x0aW1lc2hhcmluZywgbjoKCUFuIGFjY2VzcyBt
+ZXRob2Qgd2hlcmVieSBvbmUgY29tcHV0ZXIgYWJ1c2VzIG1hbnkgcGVvcGxlLgqQ
+DQMAAhEtcnzHaGl3NAGtAQdiA21zZ0QMUlpJIHRoaW5rIHRoYXQgYWxsIHJpZ2h0
+LXRoaW5raW5nIHBlb3BsZSBpbiB0aGlzIGNvdW50cnkgYXJlIHNpY2sgYW5kCnRp
+cmVkIG9mIGJlaW5nIHRvbGQgdGhhdCBvcmRpbmFyeSBkZWNlbnQgcGVvcGxlIGFy
+ZSBmZWQgdXAgaW4gdGhpcwpjb3VudHJ5IHdpdGggYmVpbmcgc2ljayBhbmQgdGly
+ZWQuICBJJ20gY2VydGFpbmx5IG5vdC4gIEJ1dCBJJ20Kc2ljayBhbmQgdGlyZWQg
+b2YgYmVpbmcgdG9sZCB0aGF0IEkgYW0uCi0gTW9udHkgUHl0aG9uCog/AwUARAxS
+Wi1yfMdoaXc0EQJHggCgmUQZNj5seMPYdi4KLEtAKaTTWlsAoIiOTMs4CaRk2bQP
+yW5Pvxz/XHjl
+=UNM4
+-----END PGP MESSAGE-----
+")
+
+;; A signed message suffixed with an unsigned literal packet.
+;; (fols = faked-literal-data, one-pass, literal-data, signature)
+;; This should throw an error because running gpg to extract the
+;; signed data will return both literal data packets
+(define bad_olsf_asc "
+-----BEGIN PGP MESSAGE-----
+
+kA0DAAIRLXJ8x2hpdzQBrQEHYgNtc2dEDFJaSSB0aGluayB0aGF0IGFsbCByaWdo
+dC10aGlua2luZyBwZW9wbGUgaW4gdGhpcyBjb3VudHJ5IGFyZSBzaWNrIGFuZAp0
+aXJlZCBvZiBiZWluZyB0b2xkIHRoYXQgb3JkaW5hcnkgZGVjZW50IHBlb3BsZSBh
+cmUgZmVkIHVwIGluIHRoaXMKY291bnRyeSB3aXRoIGJlaW5nIHNpY2sgYW5kIHRp
+cmVkLiAgSSdtIGNlcnRhaW5seSBub3QuICBCdXQgSSdtCnNpY2sgYW5kIHRpcmVk
+IG9mIGJlaW5nIHRvbGQgdGhhdCBJIGFtLgotIE1vbnR5IFB5dGhvbgqIPwMFAEQM
+UlotcnzHaGl3NBECR4IAoJlEGTY+bHjD2HYuCixLQCmk01pbAKCIjkzLOAmkZNm0
+D8luT78c/1x45axdYgxtc2cudW5zaWduZWREDGNMdGltZXNoYXJpbmcsIG46CglB
+biBhY2Nlc3MgbWV0aG9kIHdoZXJlYnkgb25lIGNvbXB1dGVyIGFidXNlcyBtYW55
+IHBlb3BsZS4K
+=3gnG
+-----END PGP MESSAGE-----
+")
+
+
+;; Two standard signed messages in a row
+(define msg_olsols_asc_multiple "
+-----BEGIN PGP MESSAGE-----
+
+kA0DAAIRLXJ8x2hpdzQBrQEHYgNtc2dEDFJaSSB0aGluayB0aGF0IGFsbCByaWdo
+dC10aGlua2luZyBwZW9wbGUgaW4gdGhpcyBjb3VudHJ5IGFyZSBzaWNrIGFuZAp0
+aXJlZCBvZiBiZWluZyB0b2xkIHRoYXQgb3JkaW5hcnkgZGVjZW50IHBlb3BsZSBh
+cmUgZmVkIHVwIGluIHRoaXMKY291bnRyeSB3aXRoIGJlaW5nIHNpY2sgYW5kIHRp
+cmVkLiAgSSdtIGNlcnRhaW5seSBub3QuICBCdXQgSSdtCnNpY2sgYW5kIHRpcmVk
+IG9mIGJlaW5nIHRvbGQgdGhhdCBJIGFtLgotIE1vbnR5IFB5dGhvbgqIPwMFAEQM
+UlotcnzHaGl3NBECR4IAoJlEGTY+bHjD2HYuCixLQCmk01pbAKCIjkzLOAmkZNm0
+D8luT78c/1x45ZANAwACES1yfMdoaXc0Aa0BB2IDbXNnRAxSWkkgdGhpbmsgdGhh
+dCBhbGwgcmlnaHQtdGhpbmtpbmcgcGVvcGxlIGluIHRoaXMgY291bnRyeSBhcmUg
+c2ljayBhbmQKdGlyZWQgb2YgYmVpbmcgdG9sZCB0aGF0IG9yZGluYXJ5IGRlY2Vu
+dCBwZW9wbGUgYXJlIGZlZCB1cCBpbiB0aGlzCmNvdW50cnkgd2l0aCBiZWluZyBz
+aWNrIGFuZCB0aXJlZC4gIEknbSBjZXJ0YWlubHkgbm90LiAgQnV0IEknbQpzaWNr
+IGFuZCB0aXJlZCBvZiBiZWluZyB0b2xkIHRoYXQgSSBhbS4KLSBNb250eSBQeXRo
+b24KiD8DBQBEDFJaLXJ8x2hpdzQRAkeCAKCZRBk2Pmx4w9h2LgosS0AppNNaWwCg
+iI5MyzgJpGTZtA/Jbk+/HP9ceOU=
+=8nLN
+-----END PGP MESSAGE-----
+")
+
+;; A standard message with two signatures (actually the same signature
+;; duplicated).
+(define msg_oolss_asc "
+-----BEGIN PGP MESSAGE-----
+
+kA0DAAIRLXJ8x2hpdzQBkA0DAAIRLXJ8x2hpdzQBrQEHYgNtc2dEDFJaSSB0aGlu
+ayB0aGF0IGFsbCByaWdodC10aGlua2luZyBwZW9wbGUgaW4gdGhpcyBjb3VudHJ5
+IGFyZSBzaWNrIGFuZAp0aXJlZCBvZiBiZWluZyB0b2xkIHRoYXQgb3JkaW5hcnkg
+ZGVjZW50IHBlb3BsZSBhcmUgZmVkIHVwIGluIHRoaXMKY291bnRyeSB3aXRoIGJl
+aW5nIHNpY2sgYW5kIHRpcmVkLiAgSSdtIGNlcnRhaW5seSBub3QuICBCdXQgSSdt
+CnNpY2sgYW5kIHRpcmVkIG9mIGJlaW5nIHRvbGQgdGhhdCBJIGFtLgotIE1vbnR5
+IFB5dGhvbgqIPwMFAEQMUlotcnzHaGl3NBECR4IAoJlEGTY+bHjD2HYuCixLQCmk
+01pbAKCIjkzLOAmkZNm0D8luT78c/1x45Yg/AwUARAxSWi1yfMdoaXc0EQJHggCg
+mUQZNj5seMPYdi4KLEtAKaTTWlsAoIiOTMs4CaRk2bQPyW5Pvxz/XHjl
+=KVw5
+-----END PGP MESSAGE-----
+")
+
+;; A standard message with two one-pass packet but only one signature
+;; packet
+(define bad_ools_asc "
+-----BEGIN PGP MESSAGE-----
+
+kA0DAAIRLXJ8x2hpdzQBkA0DAAIRLXJ8x2hpdzQBrQEHYgNtc2dEDFJaSSB0aGlu
+ayB0aGF0IGFsbCByaWdodC10aGlua2luZyBwZW9wbGUgaW4gdGhpcyBjb3VudHJ5
+IGFyZSBzaWNrIGFuZAp0aXJlZCBvZiBiZWluZyB0b2xkIHRoYXQgb3JkaW5hcnkg
+ZGVjZW50IHBlb3BsZSBhcmUgZmVkIHVwIGluIHRoaXMKY291bnRyeSB3aXRoIGJl
+aW5nIHNpY2sgYW5kIHRpcmVkLiAgSSdtIGNlcnRhaW5seSBub3QuICBCdXQgSSdt
+CnNpY2sgYW5kIHRpcmVkIG9mIGJlaW5nIHRvbGQgdGhhdCBJIGFtLgotIE1vbnR5
+IFB5dGhvbgqIPwMFAEQMUlotcnzHaGl3NBECR4IAoJlEGTY+bHjD2HYuCixLQCmk
+01pbAKCIjkzLOAmkZNm0D8luT78c/1x45Q==
+=1/ix
+-----END PGP MESSAGE-----
+")
+
+;; Standard cleartext signature
+(define msg_cls_asc "
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+I think that all right-thinking people in this country are sick and
+tired of being told that ordinary decent people are fed up in this
+country with being sick and tired.  I'm certainly not.  But I'm
+sick and tired of being told that I am.
+- - Monty Python
+-----BEGIN PGP SIGNATURE-----
+
+iD8DBQFEDVp1LXJ8x2hpdzQRAplUAKCMfpG3GPw/TLN52tosgXP5lNECkwCfQhAa
+emmev7IuQjWYrGF9Lxj+zj8=
+=qJsY
+-----END PGP SIGNATURE-----
+")
+
+;; Cleartext signature with two signatures
+(define msg_clss_asc "
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+What is the difference between a Turing machine and the modern computer?
+It's the same as that between Hillary's ascent of Everest and the
+establishment of a Hilton on its peak.
+-----BEGIN PGP SIGNATURE-----
+
+iD8DBQFEDVz6LXJ8x2hpdzQRAtkGAKCeMhNbHnh339fpjNj9owsYcC4zBwCfYO5l
+2u+KEfXX0FKyk8SMzLjZ536IPwMFAUQNXPr+GAsdqeOwshEC2QYAoPOWAiQm0EF/
+FWIAQUplk7JWbyRKAJ92ZJyJpWfzb0yc1s7MY65r2qEHrg==
+=1Xvv
+-----END PGP SIGNATURE-----
+")
+
+;; Two clear text signatures in a row
+(define msg_clsclss_asc_multiple (string-append msg_cls_asc msg_clss_asc))
+
+;; Fixme:  We need more tests with manipulated cleartext signatures.
+
+;;
+;; Now run the tests.
+;;
+(for-each-p
+ "Checking that a valid signature is verified as such"
+ (lambda (armored-file)
+   (pipe:do
+    (pipe:echo (eval armored-file (current-environment)))
+    (pipe:spawn `(,@GPG --verify))))
+ '(msg_ols_asc msg_cols_asc msg_sl_asc msg_oolss_asc msg_cls_asc msg_clss_asc))
+
+(for-each-p
+ "Checking that a valid signature over multiple messages is verified as such"
+ (lambda (armored-file)
+   (pipe:do
+    (pipe:echo (eval armored-file (current-environment)))
+    (pipe:spawn `(,@GPG --verify --allow-multiple-messages)))
+   (catch '()
+         (pipe:do
+          (pipe:defer (lambda (sink)
+                        (display armored-file (fdopen sink "w"))))
+          (pipe:spawn `(,@GPG --verify)))
+         (error "verification succeded but should not")))
+ '(msg_olsols_asc_multiple msg_clsclss_asc_multiple))
+
+(for-each-p
+ "Checking that an invalid signature is verified as such"
+ (lambda (armored-file)
+   (catch '()
+         (pipe:do
+          (pipe:echo (eval armored-file (current-environment)))
+          (pipe:spawn `(,@GPG --verify)))
+         (error "verification succeded but should not")))
+ '(bad_ls_asc bad_fols_asc bad_olsf_asc bad_ools_asc))
diff --git a/tests/openpgp/version.scm b/tests/openpgp/version.scm
new file mode 100755 (executable)
index 0000000..57efb93
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env gpgscm
+
+;; Copyright (C) 2016 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(load (with-path "defs.scm"))
+
+(info "Printing the GPG version")
+(assert (string-contains? (call-check `(,@GPG --version))
+                         "gpg (GnuPG) 2."))
index d43ede8..7bc1456 100644 (file)
@@ -51,9 +51,17 @@ else
   gpgtar =
 endif
 
+if BUILD_WKS_TOOLS
+  gpg_wks_server = gpg-wks-server
+  gpg_wks_client = gpg-wks-client
+else
+  gpg_wks_server =
+  gpg_wks_client =
+endif
+
 bin_PROGRAMS = gpgconf gpg-connect-agent ${symcryptrun}
 if !HAVE_W32_SYSTEM
-bin_PROGRAMS += watchgnupg gpgparsemail
+bin_PROGRAMS += watchgnupg gpgparsemail ${gpg_wks_server} ${gpg_wks_client}
 endif
 if !HAVE_W32CE_SYSTEM
 bin_PROGRAMS += ${gpgtar}
@@ -136,6 +144,34 @@ gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS)
 gpgtar_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
                $(LIBINTL) $(NETLIBS) $(LIBICONV) $(W32SOCKLIBS)
 
+gpg_wks_server_SOURCES = \
+       gpg-wks-server.c \
+       gpg-wks.h \
+       wks-util.c \
+       wks-receive.c \
+       rfc822parse.c rfc822parse.h \
+       mime-parser.c mime-parser.h \
+       mime-maker.c  mime-maker.h  \
+       send-mail.c   send-mail.h
+
+gpg_wks_server_CFLAGS = $(GPG_ERROR_CFLAGS)
+gpg_wks_server_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS)
+
+gpg_wks_client_SOURCES = \
+       gpg-wks-client.c \
+       gpg-wks.h  \
+       wks-util.c \
+       wks-receive.c \
+       rfc822parse.c rfc822parse.h \
+       mime-parser.c mime-parser.h \
+       mime-maker.h  mime-maker.c  \
+       send-mail.c   send-mail.h   \
+       call-dirmngr.c call-dirmngr.h
+
+gpg_wks_client_CFLAGS = $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
+gpg_wks_client_LDADD = $(libcommon) \
+                      $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS)
+
 
 # Make sure that all libs are build before we use them.  This is
 # important for things like make -j2.
diff --git a/tools/call-dirmngr.c b/tools/call-dirmngr.c
new file mode 100644 (file)
index 0000000..0e591dd
--- /dev/null
@@ -0,0 +1,205 @@
+/* call-dirmngr.c - Interact with the Dirmngr.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include <assuan.h>
+#include "util.h"
+#include "i18n.h"
+#include "asshelp.h"
+#include "mbox-util.h"
+#include "./call-dirmngr.h"
+
+static struct
+{
+  int verbose;
+  int debug_ipc;
+  int autostart;
+} opt;
+
+
+
+void
+set_dirmngr_options (int verbose, int debug_ipc, int autostart)
+{
+  opt.verbose = verbose;
+  opt.debug_ipc = debug_ipc;
+  opt.autostart = autostart;
+}
+
+
+/* Connect to the Dirmngr and return an assuan context.  */
+static gpg_error_t
+connect_dirmngr (assuan_context_t *r_ctx)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+
+  *r_ctx = NULL;
+  err = start_new_dirmngr (&ctx,
+                           GPG_ERR_SOURCE_DEFAULT,
+                           NULL,
+                           opt.autostart, opt.verbose, opt.debug_ipc,
+                           NULL, NULL);
+  if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
+    {
+      static int shown;
+
+      if (!shown)
+        {
+          shown = 1;
+          log_info (_("no dirmngr running in this session\n"));
+        }
+    }
+
+  if (err)
+    assuan_release (ctx);
+  else
+    {
+      *r_ctx = ctx;
+    }
+
+  return err;
+}
+
+
+
+\f
+/* Parameter structure used with the WKD_GET command.  */
+struct wkd_get_parm_s
+{
+  estream_t memfp;
+};
+
+
+/* Data callback for the WKD_GET command. */
+static gpg_error_t
+wkd_get_data_cb (void *opaque, const void *data, size_t datalen)
+{
+  struct wkd_get_parm_s *parm = opaque;
+  gpg_error_t err = 0;
+  size_t nwritten;
+
+  if (!data)
+    return 0;  /* Ignore END commands.  */
+  if (!parm->memfp)
+    return 0;  /* Data is not required.  */
+
+  if (es_write (parm->memfp, data, datalen, &nwritten))
+    err = gpg_error_from_syserror ();
+
+  return err;
+}
+
+
+/* Status callback for the WKD_GET command.  */
+static gpg_error_t
+wkd_get_status_cb (void *opaque, const char *line)
+{
+  struct wkd_get_parm_s *parm = opaque;
+  gpg_error_t err = 0;
+
+  (void)line;
+  (void)parm;
+
+  return err;
+}
+
+
+/* Ask the dirmngr for the submission address of a WKD server for the
+ * mail address ADDRSPEC.  On success the submission address is stored
+ * at R_ADDRSPEC.  */
+gpg_error_t
+wkd_get_submission_address (const char *addrspec, char **r_addrspec)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  struct wkd_get_parm_s parm;
+  char *line = NULL;
+  void *vp;
+  char *buffer = NULL;
+  char *p;
+
+  memset (&parm, 0, sizeof parm);
+  *r_addrspec = NULL;
+
+  err = connect_dirmngr (&ctx);
+  if (err)
+    return err;
+
+  line = es_bsprintf ("WKD_GET --submission-address -- %s", addrspec);
+  if (!line)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
+    {
+      err = gpg_error (GPG_ERR_TOO_LARGE);
+      goto leave;
+    }
+
+  parm.memfp = es_fopenmem (0, "rwb");
+  if (!parm.memfp)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
+                         NULL, NULL, wkd_get_status_cb, &parm);
+  if (err)
+    goto leave;
+
+  es_fputc (0, parm.memfp);
+  if (es_fclose_snatch (parm.memfp, &vp, NULL))
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  buffer = vp;
+  parm.memfp = NULL;
+  p = strchr (buffer, '\n');
+  if (p)
+    *p = 0;
+  trim_spaces (buffer);
+  if (!is_valid_mailbox (buffer))
+    {
+      err = gpg_error (GPG_ERR_INV_USER_ID);
+      goto leave;
+    }
+  *r_addrspec = xtrystrdup (buffer);
+  if (!*r_addrspec)
+    err = gpg_error_from_syserror ();
+
+ leave:
+  es_free (buffer);
+  es_fclose (parm.memfp);
+  xfree (line);
+  assuan_release (ctx);
+  return err;
+}
diff --git a/tools/call-dirmngr.h b/tools/call-dirmngr.h
new file mode 100644 (file)
index 0000000..f1bc368
--- /dev/null
@@ -0,0 +1,28 @@
+/* call-dirmngr.h - Interact with the Dirmngr.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef GNUPG_TOOLS_CALL_DIRMNGR_H
+#define GNUPG_TOOLS_CALL_DIRMNGR_H
+
+void set_dirmngr_options (int verbose, int debug_ipc, int autostart);
+
+gpg_error_t wkd_get_submission_address (const char *addrspec,
+                                        char **r_addrspec);
+
+
+#endif /*GNUPG_TOOLS_CALL_DIRMNGR_H*/
index 1cd554f..6b5f507 100644 (file)
@@ -1879,6 +1879,16 @@ main (int argc, char **argv)
   if (opt.verbose)
     log_info ("closing connection to agent\n");
 
+  /* XXX: We would like to release the context here, but libassuan
+     nicely says good bye to the server, which results in a SIGPIPE if
+     the server died.  Unfortunately, libassuan does not ignore
+     SIGPIPE when used with UNIX sockets, hence we simply leak the
+     context here.  */
+  if (0)
+    assuan_release (ctx);
+  else
+    gpgrt_annotate_leaked_object (ctx);
+  xfree (line);
   return 0;
 }
 
diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c
new file mode 100644 (file)
index 0000000..2ee23d7
--- /dev/null
@@ -0,0 +1,758 @@
+/* gpg-wks-client.c - A client for the Web Key Service protocols.
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "i18n.h"
+#include "sysutils.h"
+#include "init.h"
+#include "asshelp.h"
+#include "userids.h"
+#include "ccparray.h"
+#include "exectool.h"
+#include "mbox-util.h"
+#include "name-value.h"
+#include "call-dirmngr.h"
+#include "mime-maker.h"
+#include "send-mail.h"
+#include "gpg-wks.h"
+
+
+/* Constants to identify the commands and options. */
+enum cmd_and_opt_values
+  {
+    aNull = 0,
+
+    oQuiet      = 'q',
+    oVerbose   = 'v',
+    oOutput     = 'o',
+
+    oDebug      = 500,
+
+    aCreate,
+    aReceive,
+    aRead,
+
+    oGpgProgram,
+    oSend,
+
+    oDummy
+  };
+
+
+/* The list of commands and options. */
+static ARGPARSE_OPTS opts[] = {
+  ARGPARSE_group (300, ("@Commands:\n ")),
+
+  ARGPARSE_c (aCreate,   "create",
+              ("create a publication request")),
+  ARGPARSE_c (aReceive,   "receive",
+              ("receive a MIME confirmation request")),
+  ARGPARSE_c (aRead,      "read",
+              ("receive a plain text confirmation request")),
+
+  ARGPARSE_group (301, ("@\nOptions:\n ")),
+
+  ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
+  ARGPARSE_s_n (oQuiet,        "quiet",  ("be somewhat more quiet")),
+  ARGPARSE_s_s (oDebug, "debug", "@"),
+  ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
+  ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
+  ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
+
+
+  ARGPARSE_end ()
+};
+
+
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_CRYPTO_VALUE , "crypto"  },
+    { DBG_MEMORY_VALUE , "memory"  },
+    { DBG_MEMSTAT_VALUE, "memstat" },
+    { DBG_IPC_VALUE    , "ipc"     },
+    { DBG_EXTPROG_VALUE, "extprog" },
+    { 0, NULL }
+  };
+
+
+static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
+static gpg_error_t command_send (const char *fingerprint, char *userid);
+static gpg_error_t process_confirmation_request (estream_t msg);
+static gpg_error_t command_receive_cb (void *opaque,
+                                       const char *mediatype, estream_t fp);
+
+
+\f
+/* Print usage information and and provide strings for help. */
+static const char *
+my_strusage( int level )
+{
+  const char *p;
+
+  switch (level)
+    {
+    case 11: p = "gpg-wks-client (@GNUPG@)";
+      break;
+    case 13: p = VERSION; break;
+    case 17: p = PRINTABLE_OS_NAME; break;
+    case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
+
+    case 1:
+    case 40:
+      p = ("Usage: gpg-wks-client [command] [options] [args] (-h for help)");
+      break;
+    case 41:
+      p = ("Syntax: gpg-wks-client [command] [options] [args]\n"
+           "Client for the Web Key Service\n");
+      break;
+
+    default: p = NULL; break;
+    }
+  return p;
+}
+
+
+static void
+wrong_args (const char *text)
+{
+  es_fprintf (es_stderr, _("usage: %s [options] %s\n"), strusage (11), text);
+  exit (2);
+}
+
+
+\f
+/* Command line parsing.  */
+static enum cmd_and_opt_values
+parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
+{
+  enum cmd_and_opt_values cmd = 0;
+  int no_more_options = 0;
+
+  while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
+    {
+      switch (pargs->r_opt)
+        {
+       case oQuiet:     opt.quiet = 1; break;
+        case oVerbose:   opt.verbose++; break;
+        case oDebug:
+          if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
+            {
+              pargs->r_opt = ARGPARSE_INVALID_ARG;
+              pargs->err = ARGPARSE_PRINT_ERROR;
+            }
+          break;
+
+        case oGpgProgram:
+          opt.gpg_program = pargs->r.ret_str;
+          break;
+        case oSend:
+          opt.use_sendmail = 1;
+          break;
+        case oOutput:
+          opt.output = pargs->r.ret_str;
+          break;
+
+       case aCreate:
+       case aReceive:
+       case aRead:
+          cmd = pargs->r_opt;
+          break;
+
+        default: pargs->err = 2; break;
+       }
+    }
+
+  return cmd;
+}
+
+
+\f
+/* gpg-wks-client main. */
+int
+main (int argc, char **argv)
+{
+  gpg_error_t err;
+  ARGPARSE_ARGS pargs;
+  enum cmd_and_opt_values cmd;
+
+  gnupg_reopen_std ("gpg-wks-client");
+  set_strusage (my_strusage);
+  log_set_prefix ("gpg-wks-client", GPGRT_LOG_WITH_PREFIX);
+
+  /* Make sure that our subsystems are ready.  */
+  i18n_init();
+  init_common_subsystems (&argc, &argv);
+
+  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+  setup_libassuan_logging (&opt.debug);
+
+  /* Parse the command line. */
+  pargs.argc  = &argc;
+  pargs.argv  = &argv;
+  pargs.flags = ARGPARSE_FLAG_KEEP;
+  cmd = parse_arguments (&pargs, opts);
+
+  if (log_get_errorcount (0))
+    exit (2);
+
+  /* Print a warning if an argument looks like an option.  */
+  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+    {
+      int i;
+
+      for (i=0; i < argc; i++)
+        if (argv[i][0] == '-' && argv[i][1] == '-')
+          log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
+    }
+
+  /* Set defaults for non given options.  */
+  if (!opt.gpg_program)
+    opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
+
+  /* Tell call-dirmngr what options we want.  */
+  set_dirmngr_options (opt.verbose, (opt.debug & DBG_IPC_VALUE), 1);
+
+  /* Run the selected command.  */
+  switch (cmd)
+    {
+    case aCreate:
+      if (argc != 2)
+        wrong_args ("--create FINGERPRINT USER-ID");
+      err = command_send (argv[0], argv[1]);
+      if (err)
+        log_error ("creating request failed: %s\n", gpg_strerror (err));
+      break;
+
+    case aReceive:
+      if (argc)
+        wrong_args ("--receive < MIME-DATA");
+      err = wks_receive (es_stdin, command_receive_cb, NULL);
+      if (err)
+        log_error ("processing mail failed: %s\n", gpg_strerror (err));
+      break;
+
+    case aRead:
+      if (argc)
+        wrong_args ("--read < WKS-DATA");
+      err = process_confirmation_request (es_stdin);
+      if (err)
+        log_error ("processing mail failed: %s\n", gpg_strerror (err));
+      break;
+
+    default:
+      usage (1);
+      break;
+    }
+
+  return log_get_errorcount (0)? 1:0;
+}
+
+
+\f
+struct get_key_status_parm_s
+{
+  const char *fpr;
+  int found;
+  int count;
+};
+
+static void
+get_key_status_cb (void *opaque, const char *keyword, char *args)
+{
+  struct get_key_status_parm_s *parm = opaque;
+
+  /*log_debug ("%s: %s\n", keyword, args);*/
+  if (!strcmp (keyword, "EXPORTED"))
+    {
+      parm->count++;
+      if (!ascii_strcasecmp (args, parm->fpr))
+        parm->found = 1;
+    }
+}
+
+
+/* Get a key by fingerprint from gpg's keyring and make sure that the
+ * mail address ADDRSPEC is included in the key.  The key is returned
+ * as a new memory stream at R_KEY.
+ *
+ * Fixme: After we have implemented import and export filters for gpg
+ * this function shall only return a key with just this user id.  */
+static gpg_error_t
+get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv = NULL;
+  estream_t key = NULL;
+  struct get_key_status_parm_s parm;
+  char *filterexp = NULL;
+
+  memset (&parm, 0, sizeof parm);
+
+  *r_key = NULL;
+
+  key = es_fopenmem (0, "w+b");
+  if (!key)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  filterexp = es_bsprintf ("keep-uid=mbox = %s", addrspec);
+  if (!filterexp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--no-options");
+  if (!opt.verbose)
+    ccparray_put (&ccp, "--quiet");
+  else if (opt.verbose > 1)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--always-trust");
+  ccparray_put (&ccp, "--armor");
+  ccparray_put (&ccp, "--export-options=export-minimal");
+  ccparray_put (&ccp, "--export-filter");
+  ccparray_put (&ccp, filterexp);
+  ccparray_put (&ccp, "--export");
+  ccparray_put (&ccp, "--");
+  ccparray_put (&ccp, fingerprint);
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  parm.fpr = fingerprint;
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
+                                NULL, key,
+                                get_key_status_cb, &parm);
+  if (!err && parm.count > 1)
+    err = gpg_error (GPG_ERR_TOO_MANY);
+  else if (!err && !parm.found)
+    err = gpg_error (GPG_ERR_NOT_FOUND);
+  if (err)
+    {
+      log_error ("export failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  es_rewind (key);
+  *r_key = key;
+  key = NULL;
+
+ leave:
+  es_fclose (key);
+  xfree (argv);
+  xfree (filterexp);
+  return err;
+}
+
+
+\f
+/* Locate the key by fingerprint and userid and send a publication
+ * request.  */
+static gpg_error_t
+command_send (const char *fingerprint, char *userid)
+{
+  gpg_error_t err;
+  KEYDB_SEARCH_DESC desc;
+  char *addrspec = NULL;
+  estream_t key = NULL;
+  char *submission_to = NULL;
+  mime_maker_t mime = NULL;
+
+  if (classify_user_id (fingerprint, &desc, 1)
+      || !(desc.mode == KEYDB_SEARCH_MODE_FPR
+           || desc.mode == KEYDB_SEARCH_MODE_FPR20))
+    {
+      log_error (_("\"%s\" is not a fingerprint\n"), fingerprint);
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
+  addrspec = mailbox_from_userid (userid);
+  if (!addrspec)
+    {
+      log_error (_("\"%s\" is not a proper mail address\n"), userid);
+      err = gpg_error (GPG_ERR_INV_USER_ID);
+      goto leave;
+    }
+  err = get_key (&key, fingerprint, addrspec);
+  if (err)
+    goto leave;
+
+  /* Get the submission address.  */
+  err = wkd_get_submission_address (addrspec, &submission_to);
+  if (err)
+    goto leave;
+  log_info ("submitting request to '%s'\n", submission_to);
+
+  /* Send the key.  */
+  err = mime_maker_new (&mime, NULL);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "From", addrspec);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "To", submission_to);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "Subject", "Key publishing request");
+  if (err)
+    goto leave;
+
+  err = mime_maker_add_header (mime, "Content-type", "application/pgp-keys");
+  if (err)
+    goto leave;
+
+  err = mime_maker_add_stream (mime, &key);
+  if (err)
+    goto leave;
+
+  err = wks_send_mime (mime);
+
+ leave:
+  mime_maker_release (mime);
+  xfree (submission_to);
+  es_fclose (key);
+  xfree (addrspec);
+  return err;
+}
+
+
+\f
+static void
+encrypt_response_status_cb (void *opaque, const char *keyword, char *args)
+{
+  gpg_error_t *failure = opaque;
+  char *fields[2];
+
+  if (opt.debug)
+    log_debug ("%s: %s\n", keyword, args);
+
+  if (!strcmp (keyword, "FAILURE"))
+    {
+      if (split_fields (args, fields, DIM (fields)) >= 2
+          && !strcmp (fields[0], "encrypt"))
+        *failure = strtoul (fields[1], NULL, 10);
+    }
+
+}
+
+
+/* Encrypt the INPUT stream to a new stream which is stored at success
+ * at R_OUTPUT.  Encryption is done for ADDRSPEC.  We currently
+ * retrieve that key from the WKD, DANE, or from "local".  "local" is
+ * last to prefer the latest key version but use a local copy in case
+ * we are working offline.  It might be useful for the server to send
+ * the fingerprint of its encryption key - or even the entire key
+ * back.  */
+static gpg_error_t
+encrypt_response (estream_t *r_output, estream_t input, const char *addrspec)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+  estream_t output;
+  gpg_error_t gpg_err = 0;
+
+  *r_output = NULL;
+
+  output = es_fopenmem (0, "w+b");
+  if (!output)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--no-options");
+  if (!opt.verbose)
+    ccparray_put (&ccp, "--quiet");
+  else if (opt.verbose > 1)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--always-trust");
+  ccparray_put (&ccp, "--armor");
+  ccparray_put (&ccp, "--auto-key-locate=clear,wkd,dane,local");
+  ccparray_put (&ccp, "--recipient");
+  ccparray_put (&ccp, addrspec);
+  ccparray_put (&ccp, "--encrypt");
+  ccparray_put (&ccp, "--");
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
+                                NULL, output,
+                                encrypt_response_status_cb, &gpg_err);
+  if (err)
+    {
+      if (gpg_err)
+        err = gpg_err;
+      log_error ("encryption failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  es_rewind (output);
+  *r_output = output;
+  output = NULL;
+
+ leave:
+  es_fclose (output);
+  xfree (argv);
+  return err;
+}
+
+
+static gpg_error_t
+send_confirmation_response (const char *sender, const char *address,
+                            const char *nonce, int encrypt)
+{
+  gpg_error_t err;
+  estream_t body = NULL;
+  estream_t bodyenc = NULL;
+  mime_maker_t mime = NULL;
+
+  body = es_fopenmem (0, "w+b");
+  if (!body)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  /* It is fine to use 8 bit encoding because that is encrypted and
+   * only our client will see it.  */
+  if (encrypt)
+    {
+      es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
+                "Content-Transfer-Encoding: 8bit\n"
+                "\n",
+                body);
+    }
+
+  es_fprintf (body, ("type: confirmation-response\n"
+                     "sender: %s\n"
+                     "address: %s\n"
+                     "nonce: %s\n"),
+              sender,
+              address,
+              nonce);
+
+  es_rewind (body);
+  if (encrypt)
+    {
+      err = encrypt_response (&bodyenc, body, sender);
+      if (err)
+        goto leave;
+      es_fclose (body);
+      body = NULL;
+    }
+
+  err = mime_maker_new (&mime, NULL);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "From", address);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "To", sender);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "Subject", "Key publication confirmation");
+  if (err)
+    goto leave;
+
+  if (encrypt)
+    {
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "multipart/encrypted; "
+                                   "protocol=\"application/pgp-encrypted\"");
+      if (err)
+        goto leave;
+      err = mime_maker_add_container (mime, "multipart/encrypted");
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "application/pgp-encrypted");
+      if (err)
+        goto leave;
+      err = mime_maker_add_body (mime, "Version: 1\n");
+      if (err)
+        goto leave;
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "application/octet-stream");
+      if (err)
+        goto leave;
+
+      err = mime_maker_add_stream (mime, &bodyenc);
+      if (err)
+        goto leave;
+    }
+  else
+    {
+      err = mime_maker_add_header (mime, "Content-Type",
+                                   "application/vnd.gnupg.wks");
+      if (err)
+        goto leave;
+      err = mime_maker_add_stream (mime, &body);
+      if (err)
+        goto leave;
+    }
+
+  err = wks_send_mime (mime);
+
+ leave:
+  mime_maker_release (mime);
+  es_fclose (bodyenc);
+  es_fclose (body);
+  return err;
+}
+
+
+/* Reply to a confirmation request.  The MSG has already been
+ * decrypted and we only need to send the nonce back.  */
+static gpg_error_t
+process_confirmation_request (estream_t msg)
+{
+  gpg_error_t err;
+  nvc_t nvc;
+  nve_t item;
+  const char *value, *sender, *address, *nonce;
+
+  err = nvc_parse (&nvc, NULL, msg);
+  if (err)
+    {
+      log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  if (opt.debug)
+    {
+      log_debug ("request follows:\n");
+      nvc_write (nvc, log_get_stream ());
+    }
+
+  /* Check that this is a confirmation request.  */
+  if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
+        && !strcmp (value, "confirmation-request")))
+    {
+      if (item && value)
+        log_error ("received unexpected wks message '%s'\n", value);
+      else
+        log_error ("received invalid wks message: %s\n", "'type' missing");
+      err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
+      goto leave;
+    }
+
+  /* FIXME: Check that the fingerprint matches the key used to decrypt the
+   * message.  */
+
+  /* Get the address.  */
+  if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
+        && is_valid_mailbox (value)))
+    {
+      log_error ("received invalid wks message: %s\n",
+                 "'address' missing or invalid");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  address = value;
+  /* FIXME: Check that the "address" matches the User ID we want to
+   * publish.  */
+
+  /* Get the sender.  */
+  if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
+        && is_valid_mailbox (value)))
+    {
+      log_error ("received invalid wks message: %s\n",
+                 "'sender' missing or invalid");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  sender = value;
+  /* FIXME: Check that the "sender" matches the From: address.  */
+
+  /* Get the nonce.  */
+  if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
+        && strlen (value) > 16))
+    {
+      log_error ("received invalid wks message: %s\n",
+                 "'nonce' missing or too short");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  nonce = value;
+
+  /* Send the confirmation.  If no key was found, try again without
+   * encryption.  */
+  err = send_confirmation_response (sender, address, nonce, 1);
+  if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+    {
+      log_info ("no encryption key found - sending response in the clear\n");
+      err = send_confirmation_response (sender, address, nonce, 0);
+    }
+
+ leave:
+  nvc_release (nvc);
+  return err;
+}
+
+
+/* Called from the MIME receiver to process the plain text data in MSG.  */
+static gpg_error_t
+command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
+{
+  gpg_error_t err;
+
+  (void)opaque;
+
+  if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
+    err = process_confirmation_request (msg);
+  else
+    {
+      log_info ("ignoring unexpected message of type '%s'\n", mediatype);
+      err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
+    }
+
+  return err;
+}
diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c
new file mode 100644 (file)
index 0000000..f15085f
--- /dev/null
@@ -0,0 +1,1548 @@
+/* gpg-wks-server.c - A server for the Web Key Service protocols.
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* The Web Key Service I-D defines an update protocol to stpre a
+ * public key in the Web Key Directory.  The current specification is
+ * draft-koch-openpgp-webkey-service-01.txt.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "util.h"
+#include "init.h"
+#include "sysutils.h"
+#include "ccparray.h"
+#include "exectool.h"
+#include "zb32.h"
+#include "mbox-util.h"
+#include "name-value.h"
+#include "mime-maker.h"
+#include "send-mail.h"
+#include "gpg-wks.h"
+
+
+/* The time we wait for a confirmation response.  */
+#define PENDING_TTL (86400 * 3)  /* 3 days.  */
+
+
+/* Constants to identify the commands and options. */
+enum cmd_and_opt_values
+  {
+    aNull = 0,
+
+    oQuiet      = 'q',
+    oVerbose   = 'v',
+    oOutput     = 'o',
+
+    oDebug      = 500,
+
+    aReceive,
+    aCron,
+    aListDomains,
+
+    oGpgProgram,
+    oSend,
+    oFrom,
+    oHeader,
+
+    oDummy
+  };
+
+
+/* The list of commands and options. */
+static ARGPARSE_OPTS opts[] = {
+  ARGPARSE_group (300, ("@Commands:\n ")),
+
+  ARGPARSE_c (aReceive,   "receive",
+              ("receive a submission or confirmation")),
+  ARGPARSE_c (aCron,      "cron",
+              ("run regular jobs")),
+  ARGPARSE_c (aListDomains, "list-domains",
+              ("list configured domains")),
+
+  ARGPARSE_group (301, ("@\nOptions:\n ")),
+
+  ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
+  ARGPARSE_s_n (oQuiet,        "quiet",  ("be somewhat more quiet")),
+  ARGPARSE_s_s (oDebug, "debug", "@"),
+  ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
+  ARGPARSE_s_n (oSend, "send", "send the mail using sendmail"),
+  ARGPARSE_s_s (oOutput, "output", "|FILE|write the mail to FILE"),
+  ARGPARSE_s_s (oFrom, "from", "|ADDR|use ADDR as the default sender"),
+  ARGPARSE_s_s (oHeader, "header" ,
+                "|NAME=VALUE|add \"NAME: VALUE\" as header to all mails"),
+
+  ARGPARSE_end ()
+};
+
+
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_CRYPTO_VALUE , "crypto"  },
+    { DBG_MEMORY_VALUE , "memory"  },
+    { DBG_MEMSTAT_VALUE, "memstat" },
+    { DBG_IPC_VALUE    , "ipc"     },
+    { DBG_EXTPROG_VALUE, "extprog" },
+    { 0, NULL }
+  };
+
+
+/* State for processing a message.  */
+struct server_ctx_s
+{
+  char *fpr;
+  strlist_t mboxes;  /* List of addr-specs taken from the UIDs.  */
+};
+typedef struct server_ctx_s *server_ctx_t;
+
+/* Prototypes.  */
+static gpg_error_t get_domain_list (strlist_t *r_list);
+
+static gpg_error_t command_receive_cb (void *opaque,
+                                       const char *mediatype, estream_t fp);
+static gpg_error_t command_list_domains (void);
+static gpg_error_t command_cron (void);
+
+
+\f
+/* Print usage information and and provide strings for help. */
+static const char *
+my_strusage( int level )
+{
+  const char *p;
+
+  switch (level)
+    {
+    case 11: p = "gpg-wks-server (@GNUPG@)";
+      break;
+    case 13: p = VERSION; break;
+    case 17: p = PRINTABLE_OS_NAME; break;
+    case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
+
+    case 1:
+    case 40:
+      p = ("Usage: gpg-wks-server command [options] (-h for help)");
+      break;
+    case 41:
+      p = ("Syntax: gpg-wks-server command [options]\n"
+           "Server for the Web Key Service protocol\n");
+      break;
+
+    default: p = NULL; break;
+    }
+  return p;
+}
+
+
+static void
+wrong_args (const char *text)
+{
+  es_fprintf (es_stderr, "usage: %s [options] %s\n", strusage (11), text);
+  exit (2);
+}
+
+
+\f
+/* Command line parsing.  */
+static enum cmd_and_opt_values
+parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
+{
+  enum cmd_and_opt_values cmd = 0;
+  int no_more_options = 0;
+
+  while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
+    {
+      switch (pargs->r_opt)
+        {
+       case oQuiet:     opt.quiet = 1; break;
+        case oVerbose:   opt.verbose++; break;
+        case oDebug:
+          if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
+            {
+              pargs->r_opt = ARGPARSE_INVALID_ARG;
+              pargs->err = ARGPARSE_PRINT_ERROR;
+            }
+          break;
+
+        case oGpgProgram:
+          opt.gpg_program = pargs->r.ret_str;
+          break;
+        case oFrom:
+          opt.default_from = pargs->r.ret_str;
+          break;
+        case oHeader:
+          append_to_strlist (&opt.extra_headers, pargs->r.ret_str);
+          break;
+        case oSend:
+          opt.use_sendmail = 1;
+          break;
+        case oOutput:
+          opt.output = pargs->r.ret_str;
+          break;
+
+       case aReceive:
+        case aCron:
+        case aListDomains:
+          cmd = pargs->r_opt;
+          break;
+
+        default: pargs->err = 2; break;
+       }
+    }
+
+  return cmd;
+}
+
+
+\f
+/* gpg-wks-server main. */
+int
+main (int argc, char **argv)
+{
+  gpg_error_t err;
+  ARGPARSE_ARGS pargs;
+  enum cmd_and_opt_values cmd;
+
+  gnupg_reopen_std ("gpg-wks-server");
+  set_strusage (my_strusage);
+  log_set_prefix ("gpg-wks-server", GPGRT_LOG_WITH_PREFIX);
+
+  /* Make sure that our subsystems are ready.  */
+  init_common_subsystems (&argc, &argv);
+
+  /* Parse the command line. */
+  pargs.argc  = &argc;
+  pargs.argv  = &argv;
+  pargs.flags = ARGPARSE_FLAG_KEEP;
+  cmd = parse_arguments (&pargs, opts);
+
+  if (log_get_errorcount (0))
+    exit (2);
+
+  /* Print a warning if an argument looks like an option.  */
+  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+    {
+      int i;
+
+      for (i=0; i < argc; i++)
+        if (argv[i][0] == '-' && argv[i][1] == '-')
+          log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
+    }
+
+  /* Set defaults for non given options.  */
+  if (!opt.gpg_program)
+    opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
+
+  if (!opt.directory)
+    opt.directory = "/var/lib/gnupg/wks";
+
+  /* Check for syntax errors in the --header option to avoid later
+   * error messages with a not easy to find cause */
+  if (opt.extra_headers)
+    {
+      strlist_t sl;
+
+      for (sl = opt.extra_headers; sl; sl = sl->next)
+        {
+          err = mime_maker_add_header (NULL, sl->d, NULL);
+          if (err)
+            log_error ("syntax error in \"--header %s\": %s\n",
+                       sl->d, gpg_strerror (err));
+        }
+    }
+
+  if (log_get_errorcount (0))
+    exit (2);
+
+
+  /* Check that we have a working directory.  */
+#if defined(HAVE_STAT)
+  {
+    struct stat sb;
+
+    if (stat (opt.directory, &sb))
+      {
+        err = gpg_error_from_syserror ();
+        log_error ("error accessing directory '%s': %s\n",
+                   opt.directory, gpg_strerror (err));
+        exit (2);
+      }
+    if (!S_ISDIR(sb.st_mode))
+      {
+        log_error ("error accessing directory '%s': %s\n",
+                   opt.directory, "not a directory");
+        exit (2);
+      }
+    if (sb.st_uid != getuid())
+      {
+        log_error ("directory '%s' not owned by user\n", opt.directory);
+        exit (2);
+      }
+    if ((sb.st_mode & S_IRWXO))
+      {
+        log_error ("directory '%s' has too relaxed permissions\n",
+                   opt.directory);
+        exit (2);
+      }
+  }
+#else /*!HAVE_STAT*/
+  log_fatal ("program build w/o stat() call\n");
+#endif /*!HAVE_STAT*/
+
+  /* Run the selected command.  */
+  switch (cmd)
+    {
+    case aReceive:
+      if (argc)
+        wrong_args ("--receive");
+      err = wks_receive (es_stdin, command_receive_cb, NULL);
+      break;
+
+    case aCron:
+      if (argc)
+        wrong_args ("--cron");
+      err = command_cron ();
+      break;
+
+    case aListDomains:
+      err = command_list_domains ();
+      break;
+
+    default:
+      usage (1);
+      err = gpg_error (GPG_ERR_BUG);
+      break;
+    }
+
+  if (err)
+    log_error ("command failed: %s\n", gpg_strerror (err));
+  return log_get_errorcount (0)? 1:0;
+}
+
+
+\f
+static void
+list_key_status_cb (void *opaque, const char *keyword, char *args)
+{
+  server_ctx_t ctx = opaque;
+  (void)ctx;
+  if (opt.debug)
+    log_debug ("%s: %s\n", keyword, args);
+}
+
+
+static gpg_error_t
+list_key (server_ctx_t ctx, estream_t key)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+  estream_t listing;
+  char *line = NULL;
+  size_t length_of_line = 0;
+  size_t  maxlen;
+  ssize_t len;
+  char **fields = NULL;
+  int nfields;
+  int lnr;
+  char *mbox = NULL;
+
+  /* We store our results in the context - clear it first.  */
+  xfree (ctx->fpr);
+  ctx->fpr = NULL;
+  free_strlist (ctx->mboxes);
+  ctx->mboxes = NULL;
+
+  /* Open a memory stream.  */
+  listing = es_fopenmem (0, "w+b");
+  if (!listing)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--no-options");
+  if (!opt.verbose)
+    ccparray_put (&ccp, "--quiet");
+  else if (opt.verbose > 1)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--always-trust");
+  ccparray_put (&ccp, "--with-colons");
+  ccparray_put (&ccp, "--dry-run");
+  ccparray_put (&ccp, "--import-options=import-minimal,import-show");
+  ccparray_put (&ccp, "--import");
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
+                                NULL, listing,
+                                list_key_status_cb, ctx);
+  if (err)
+    {
+      log_error ("import failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  es_rewind (listing);
+  lnr = 0;
+  maxlen = 2048; /* Set limit.  */
+  while ((len = es_read_line (listing, &line, &length_of_line, &maxlen)) > 0)
+    {
+      lnr++;
+      if (!maxlen)
+        {
+          log_error ("received line too long\n");
+          err = gpg_error (GPG_ERR_LINE_TOO_LONG);
+          goto leave;
+        }
+      /* Strip newline and carriage return, if present.  */
+      while (len > 0
+            && (line[len - 1] == '\n' || line[len - 1] == '\r'))
+       line[--len] = '\0';
+      /* log_debug ("line '%s'\n", line); */
+
+      xfree (fields);
+      fields = strtokenize (line, ":");
+      if (!fields)
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("strtokenize failed: %s\n", gpg_strerror (err));
+          goto leave;
+        }
+      for (nfields = 0; fields[nfields]; nfields++)
+        ;
+      if (!nfields)
+        {
+          err = gpg_error (GPG_ERR_INV_ENGINE);
+          goto leave;
+        }
+      if (!strcmp (fields[0], "sec"))
+        {
+          /* gpg may return "sec" as the first record - but we do not
+           * accept secret keys.  */
+          err = gpg_error (GPG_ERR_NO_PUBKEY);
+          goto leave;
+        }
+      if (lnr == 1 && strcmp (fields[0], "pub"))
+        {
+          /* First record is not a public key.  */
+          err = gpg_error (GPG_ERR_INV_ENGINE);
+          goto leave;
+        }
+      if (lnr > 1 && !strcmp (fields[0], "pub"))
+        {
+          /* More than one public key.  */
+          err = gpg_error (GPG_ERR_TOO_MANY);
+          goto leave;
+        }
+      if (!strcmp (fields[0], "sub") || !strcmp (fields[0], "ssb"))
+        break; /* We can stop parsing here.  */
+
+      if (!strcmp (fields[0], "fpr") && nfields > 9 && !ctx->fpr)
+        {
+          ctx->fpr = xtrystrdup (fields[9]);
+          if (!ctx->fpr)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+        }
+      else if (!strcmp (fields[0], "uid") && nfields > 9)
+        {
+          /* Fixme: Unescape fields[9] */
+          xfree (mbox);
+          mbox = mailbox_from_userid (fields[9]);
+          if (mbox && !append_to_strlist_try (&ctx->mboxes, mbox))
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+        }
+    }
+  if (len < 0 || es_ferror (listing))
+    log_error ("error reading memory stream\n");
+
+ leave:
+  xfree (mbox);
+  xfree (fields);
+  es_free (line);
+  xfree (argv);
+  es_fclose (listing);
+  return err;
+}
+
+
+/* Take the key in KEYFILE and write it to DANEFILE using the DANE
+ * output format. */
+static gpg_error_t
+copy_key_as_dane (const char *keyfile, const char *danefile)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--no-options");
+  if (!opt.verbose)
+    ccparray_put (&ccp, "--quiet");
+  else if (opt.verbose > 1)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--yes");
+  ccparray_put (&ccp, "--always-trust");
+  ccparray_put (&ccp, "--no-keyring");
+  ccparray_put (&ccp, "--output");
+  ccparray_put (&ccp, danefile);
+  ccparray_put (&ccp, "--export-options=export-dane");
+  ccparray_put (&ccp, "--import-options=import-export");
+  ccparray_put (&ccp, "--import");
+  ccparray_put (&ccp, "--");
+  ccparray_put (&ccp, keyfile);
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
+                                NULL, NULL, NULL, NULL);
+  if (err)
+    {
+      log_error ("%s failed: %s\n", __func__, gpg_strerror (err));
+      goto leave;
+    }
+
+ leave:
+  xfree (argv);
+  return err;
+}
+
+
+static void
+encrypt_stream_status_cb (void *opaque, const char *keyword, char *args)
+{
+  (void)opaque;
+
+  if (opt.debug)
+    log_debug ("%s: %s\n", keyword, args);
+}
+
+
+/* Encrypt the INPUT stream to a new stream which is stored at success
+ * at R_OUTPUT.  Encryption is done for the key in file KEYFIL.  */
+static gpg_error_t
+encrypt_stream (estream_t *r_output, estream_t input, const char *keyfile)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+  estream_t output;
+
+  *r_output = NULL;
+
+  output = es_fopenmem (0, "w+b");
+  if (!output)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--no-options");
+  if (!opt.verbose)
+    ccparray_put (&ccp, "--quiet");
+  else if (opt.verbose > 1)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--always-trust");
+  ccparray_put (&ccp, "--no-keyring");
+  ccparray_put (&ccp, "--armor");
+  ccparray_put (&ccp, "--recipient-file");
+  ccparray_put (&ccp, keyfile);
+  ccparray_put (&ccp, "--encrypt");
+  ccparray_put (&ccp, "--");
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, input,
+                                NULL, output,
+                                encrypt_stream_status_cb, NULL);
+  if (err)
+    {
+      log_error ("encryption failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  es_rewind (output);
+  *r_output = output;
+  output = NULL;
+
+ leave:
+  es_fclose (output);
+  xfree (argv);
+  return err;
+}
+
+
+/* Get the submission address for address MBOX.  Caller must free the
+ * value.  If no address can be found NULL is returned.  */
+static char *
+get_submission_address (const char *mbox)
+{
+  gpg_error_t err;
+  const char *domain;
+  char *fname, *line, *p;
+  size_t n;
+  estream_t fp;
+
+  domain = strchr (mbox, '@');
+  if (!domain)
+    return NULL;
+  domain++;
+
+  fname = make_filename_try (opt.directory, domain, "submission-address", NULL);
+  if (!fname)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("make_filename failed in %s: %s\n",
+                 __func__, gpg_strerror (err));
+      return NULL;
+    }
+
+  fp = es_fopen (fname, "r");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      if (gpg_err_code (err) == GPG_ERR_ENOENT)
+        log_info ("Note: no specific submission address configured"
+                  " for domain '%s'\n", domain);
+      else
+        log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
+      xfree (fname);
+      return NULL;
+    }
+
+  line = NULL;
+  n = 0;
+  if (es_getline (&line, &n, fp) < 0)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
+      xfree (line);
+      es_fclose (fp);
+      xfree (fname);
+      return NULL;
+    }
+  es_fclose (fp);
+  xfree (fname);
+
+  p = strchr (line, '\n');
+  if (p)
+    *p = 0;
+  trim_spaces (line);
+  if (!is_valid_mailbox (line))
+    {
+      log_error ("invalid submission address for domain '%s' detected\n",
+                 domain);
+      xfree (line);
+      return NULL;
+    }
+
+  return line;
+}
+
+
+/* We store the key under the name of the nonce we will then send to
+ * the user.  On success the nonce is stored at R_NONCE and the file
+ * name at R_FNAME.  */
+static gpg_error_t
+store_key_as_pending (const char *dir, estream_t key,
+                      char **r_nonce, char **r_fname)
+{
+  gpg_error_t err;
+  char *dname = NULL;
+  char *fname = NULL;
+  char *nonce = NULL;
+  estream_t outfp = NULL;
+  char buffer[1024];
+  size_t nbytes, nwritten;
+
+  *r_nonce = NULL;
+  *r_fname = NULL;
+
+  dname = make_filename_try (dir, "pending", NULL);
+  if (!dname)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Create the nonce.  We use 20 bytes so that we don't waste a
+   * character in our zBase-32 encoding.  Using the gcrypt's nonce
+   * function is faster than using the strong random function; this is
+   * Good Enough for our purpose.  */
+  log_assert (sizeof buffer > 20);
+  gcry_create_nonce (buffer, 20);
+  nonce = zb32_encode (buffer, 8 * 20);
+  memset (buffer, 0, 20);  /* Not actually needed but it does not harm. */
+  if (!nonce)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  fname = strconcat (dname, "/", nonce, NULL);
+  if (!fname)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* With 128 bits of random we can expect that no other file exists
+   * under this name.  We use "x" to detect internal errors.  */
+  outfp = es_fopen (fname, "wbx,mode=-rw");
+  if (!outfp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
+      goto leave;
+    }
+  es_rewind (key);
+  for (;;)
+    {
+      if (es_read (key, buffer, sizeof buffer, &nbytes))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error reading '%s': %s\n",
+                     es_fname_get (key), gpg_strerror (err));
+          break;
+        }
+
+      if (!nbytes)
+        {
+          err = 0;
+          goto leave; /* Ready.  */
+        }
+      if (es_write (outfp, buffer, nbytes, &nwritten))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
+          goto leave;
+        }
+      else if (nwritten != nbytes)
+        {
+          err = gpg_error (GPG_ERR_EIO);
+          log_error ("error writing '%s': %s\n", fname, "short write");
+          goto leave;
+        }
+    }
+
+ leave:
+  if (err)
+    {
+      es_fclose (outfp);
+      gnupg_remove (fname);
+    }
+  else if (es_fclose (outfp))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
+    }
+
+  if (!err)
+    {
+      *r_nonce = nonce;
+      *r_fname = fname;
+    }
+  else
+    {
+      xfree (nonce);
+      xfree (fname);
+    }
+  xfree (dname);
+  return err;
+}
+
+
+/* Send a confirmation rewqyest.  DIR is the directory used for the
+ * address MBOX.  NONCE is the nonce we want to see in the response to
+ * this mail.  FNAME the name of the file with the key.  */
+static gpg_error_t
+send_confirmation_request (server_ctx_t ctx,
+                           const char *mbox, const char *nonce,
+                           const char *keyfile)
+{
+  gpg_error_t err;
+  estream_t body = NULL;
+  estream_t bodyenc = NULL;
+  mime_maker_t mime = NULL;
+  char *from_buffer = NULL;
+  const char *from;
+  strlist_t sl;
+
+  from = from_buffer = get_submission_address (mbox);
+  if (!from)
+    {
+      from = opt.default_from;
+      if (!from)
+        {
+          log_error ("no sender address found for '%s'\n", mbox);
+          err = gpg_error (GPG_ERR_CONFIGURATION);
+          goto leave;
+        }
+      log_info ("Note: using default sender address '%s'\n", from);
+    }
+
+  body = es_fopenmem (0, "w+b");
+  if (!body)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+  /* It is fine to use 8 bit encoding because that is encrypted and
+   * only our client will see it.  */
+  es_fputs ("Content-Type: application/vnd.gnupg.wks\n"
+            "Content-Transfer-Encoding: 8bit\n"
+            "\n",
+            body);
+
+  es_fprintf (body, ("type: confirmation-request\n"
+                     "sender: %s\n"
+                     "address: %s\n"
+                     "fingerprint: %s\n"
+                     "nonce: %s\n"),
+              from,
+              mbox,
+              ctx->fpr,
+              nonce);
+
+  es_rewind (body);
+  err = encrypt_stream (&bodyenc, body, keyfile);
+  if (err)
+    goto leave;
+  es_fclose (body);
+  body = NULL;
+
+
+  err = mime_maker_new (&mime, NULL);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "From", from);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "To", mbox);
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "Subject", "Confirm your key publication");
+  if (err)
+    goto leave;
+  for (sl = opt.extra_headers; sl; sl = sl->next)
+    {
+      err = mime_maker_add_header (mime, sl->d, NULL);
+      if (err)
+        goto leave;
+    }
+
+  err = mime_maker_add_header (mime, "Content-Type",
+                               "multipart/encrypted; "
+                               "protocol=\"application/pgp-encrypted\"");
+  if (err)
+    goto leave;
+  err = mime_maker_add_container (mime, "multipart/encrypted");
+  if (err)
+    goto leave;
+
+  err = mime_maker_add_header (mime, "Content-Type",
+                               "application/pgp-encrypted");
+  if (err)
+    goto leave;
+  err = mime_maker_add_body (mime, "Version: 1\n");
+  if (err)
+    goto leave;
+  err = mime_maker_add_header (mime, "Content-Type",
+                               "application/octet-stream");
+  if (err)
+    goto leave;
+
+  err = mime_maker_add_stream (mime, &bodyenc);
+  if (err)
+    goto leave;
+
+  err = wks_send_mime (mime);
+
+ leave:
+  mime_maker_release (mime);
+  es_fclose (bodyenc);
+  es_fclose (body);
+  xfree (from_buffer);
+  return err;
+}
+
+
+/* Store the key given by KEY into the pending directory and send a
+ * confirmation requests.  */
+static gpg_error_t
+process_new_key (server_ctx_t ctx, estream_t key)
+{
+  gpg_error_t err;
+  strlist_t sl;
+  const char *s;
+  char *dname = NULL;
+  char *nonce = NULL;
+  char *fname = NULL;
+
+  /* First figure out the user id from the key.  */
+  err = list_key (ctx, key);
+  if (err)
+    goto leave;
+  if (!ctx->fpr)
+    {
+      log_error ("error parsing key (no fingerprint)\n");
+      err = gpg_error (GPG_ERR_NO_PUBKEY);
+      goto leave;
+    }
+  log_info ("fingerprint: %s\n", ctx->fpr);
+  for (sl = ctx->mboxes; sl; sl = sl->next)
+    {
+      log_info ("  addr-spec: %s\n", sl->d);
+    }
+
+  /* Walk over all user ids and send confirmation requests for those
+   * we support.  */
+  for (sl = ctx->mboxes; sl; sl = sl->next)
+    {
+      s = strchr (sl->d, '@');
+      log_assert (s && s[1]);
+      xfree (dname);
+      dname = make_filename_try (opt.directory, s+1, NULL);
+      if (!dname)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      /* Fixme: check for proper directory permissions.  */
+      if (access (dname, W_OK))
+        {
+          log_info ("skipping address '%s': Domain not configured\n", sl->d);
+          continue;
+        }
+      log_info ("storing address '%s'\n", sl->d);
+
+      xfree (nonce);
+      xfree (fname);
+      err = store_key_as_pending (dname, key, &nonce, &fname);
+      if (err)
+        goto leave;
+
+      err = send_confirmation_request (ctx, sl->d, nonce, fname);
+      if (err)
+        goto leave;
+    }
+
+ leave:
+  if (nonce)
+    wipememory (nonce, strlen (nonce));
+  xfree (nonce);
+  xfree (fname);
+  xfree (dname);
+  return err;
+}
+
+
+\f
+/* Check that we have send a request with NONCE and publish the key.  */
+static gpg_error_t
+check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
+{
+  gpg_error_t err;
+  char *fname = NULL;
+  char *fnewname = NULL;
+  estream_t key = NULL;
+  char *hash = NULL;
+  const char *domain;
+  const char *s;
+  strlist_t sl;
+  char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
+
+  /* FIXME: There is a bug in name-value.c which adds white space for
+   * the last pair and thus we strip the nonce here until this has
+   * been fixed.  */
+  char *nonce2 = xstrdup (nonce);
+  trim_trailing_spaces (nonce2);
+  nonce = nonce2;
+
+
+  domain = strchr (address, '@');
+  log_assert (domain && domain[1]);
+  domain++;
+  fname = make_filename_try (opt.directory, domain, "pending", nonce, NULL);
+  if (!fname)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Try to open the file with the key.  */
+  key = es_fopen (fname, "rb");
+  if (!key)
+    {
+      err = gpg_error_from_syserror ();
+      if (gpg_err_code (err) == GPG_ERR_ENOENT)
+        {
+          log_info ("no pending request for '%s'\n", address);
+          err = gpg_error (GPG_ERR_NOT_FOUND);
+        }
+      else
+        log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
+      goto leave;
+    }
+
+  /* We need to get the fingerprint from the key.  */
+  err = list_key (ctx, key);
+  if (err)
+    goto leave;
+  if (!ctx->fpr)
+    {
+      log_error ("error parsing key (no fingerprint)\n");
+      err = gpg_error (GPG_ERR_NO_PUBKEY);
+      goto leave;
+    }
+  log_info ("fingerprint: %s\n", ctx->fpr);
+  for (sl = ctx->mboxes; sl; sl = sl->next)
+    log_info ("  addr-spec: %s\n", sl->d);
+
+  /* Check that the key has 'address' as a user id.  We use
+   * case-insensitive matching because the client is expected to
+   * return the address verbatim.  */
+  for (sl = ctx->mboxes; sl; sl = sl->next)
+    if (!strcmp (sl->d, address))
+      break;
+  if (!sl)
+    {
+      log_error ("error publishing key: '%s' is not a user ID of %s\n",
+                 address, ctx->fpr);
+      err = gpg_error (GPG_ERR_NO_PUBKEY);
+      goto leave;
+    }
+
+
+  /* Hash user ID and create filename.  */
+  s = strchr (address, '@');
+  log_assert (s);
+  gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, address, s - address);
+  hash = zb32_encode (shaxbuf, 8*20);
+  if (!hash)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  fnewname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
+  if (!fnewname)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Publish.  */
+  if (rename (fname, fnewname))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("renaming '%s' to '%s' failed: %s\n",
+                 fname, fnewname, gpg_strerror (err));
+      goto leave;
+    }
+
+  log_info ("key %s published for '%s'\n", ctx->fpr, address);
+
+
+  /* Try to publish as DANE record if the DANE directory exists.  */
+  xfree (fname);
+  fname = fnewname;
+  fnewname = make_filename_try (opt.directory, domain, "dane", NULL);
+  if (!fnewname)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  if (!access (fnewname, W_OK))
+    {
+      /* Yes, we have a dane directory.  */
+      s = strchr (address, '@');
+      log_assert (s);
+      gcry_md_hash_buffer (GCRY_MD_SHA256, shaxbuf, address, s - address);
+      xfree (hash);
+      hash = bin2hex (shaxbuf, 28, NULL);
+      if (!hash)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      xfree (fnewname);
+      fnewname = make_filename_try (opt.directory, domain, "dane", hash, NULL);
+      if (!fnewname)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      err = copy_key_as_dane (fname, fnewname);
+      if (err)
+        goto leave;
+      log_info ("key %s published for '%s' (DANE record)\n", ctx->fpr, address);
+    }
+
+
+ leave:
+  es_fclose (key);
+  xfree (hash);
+  xfree (fnewname);
+  xfree (fname);
+  xfree (nonce2);
+  return err;
+}
+
+
+/* Process a confirmation response in MSG.  */
+static gpg_error_t
+process_confirmation_response (server_ctx_t ctx, estream_t msg)
+{
+  gpg_error_t err;
+  nvc_t nvc;
+  nve_t item;
+  const char *value, *sender, *address, *nonce;
+
+  err = nvc_parse (&nvc, NULL, msg);
+  if (err)
+    {
+      log_error ("parsing the WKS message failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  if (opt.debug)
+    {
+      log_debug ("response follows:\n");
+      nvc_write (nvc, log_get_stream ());
+    }
+
+  /* Check that this is a confirmation response.  */
+  if (!((item = nvc_lookup (nvc, "type:")) && (value = nve_value (item))
+        && !strcmp (value, "confirmation-response")))
+    {
+      if (item && value)
+        log_error ("received unexpected wks message '%s'\n", value);
+      else
+        log_error ("received invalid wks message: %s\n", "'type' missing");
+      err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
+      goto leave;
+    }
+
+  /* Get the sender.  */
+  if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item))
+        && is_valid_mailbox (value)))
+    {
+      log_error ("received invalid wks message: %s\n",
+                 "'sender' missing or invalid");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  sender = value;
+  (void)sender;
+  /* FIXME: Do we really need the sender?.  */
+
+  /* Get the address.  */
+  if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item))
+        && is_valid_mailbox (value)))
+    {
+      log_error ("received invalid wks message: %s\n",
+                 "'address' missing or invalid");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  address = value;
+
+  /* Get the nonce.  */
+  if (!((item = nvc_lookup (nvc, "nonce:")) && (value = nve_value (item))
+        && strlen (value) > 16))
+    {
+      log_error ("received invalid wks message: %s\n",
+                 "'nonce' missing or too short");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  nonce = value;
+
+  err = check_and_publish (ctx, address, nonce);
+
+
+ leave:
+  nvc_release (nvc);
+  return err;
+}
+
+
+\f
+/* Called from the MIME receiver to process the plain text data in MSG .  */
+static gpg_error_t
+command_receive_cb (void *opaque, const char *mediatype, estream_t msg)
+{
+  gpg_error_t err;
+  struct server_ctx_s ctx;
+
+  memset (&ctx, 0, sizeof ctx);
+
+  (void)opaque;
+
+  if (!strcmp (mediatype, "application/pgp-keys"))
+    err = process_new_key (&ctx, msg);
+  else if (!strcmp (mediatype, "application/vnd.gnupg.wks"))
+    err = process_confirmation_response (&ctx, msg);
+  else
+    {
+      log_info ("ignoring unexpected message of type '%s'\n", mediatype);
+      err = gpg_error (GPG_ERR_UNEXPECTED_MSG);
+    }
+
+  xfree (ctx.fpr);
+  free_strlist (ctx.mboxes);
+
+  return err;
+}
+
+
+\f
+/* Return a list of all configured domains.  ECh list element is the
+ * top directory for for the domain.  To figure out the actual domain
+ * name strrchr(name, '/') can be used.  */
+static gpg_error_t
+get_domain_list (strlist_t *r_list)
+{
+  gpg_error_t err;
+  DIR *dir = NULL;
+  char *fname = NULL;
+  struct dirent *dentry;
+  struct stat sb;
+  strlist_t list = NULL;
+
+  *r_list = NULL;
+
+  dir = opendir (opt.directory);
+  if (!dir)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  while ((dentry = readdir (dir)))
+    {
+      if (*dentry->d_name == '.')
+        continue;
+      if (!strchr (dentry->d_name, '.'))
+        continue; /* No dot - can't be a domain subdir.  */
+
+      xfree (fname);
+      fname = make_filename_try (opt.directory, dentry->d_name, NULL);
+      if (!fname)
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("make_filename failed in %s: %s\n",
+                     __func__, gpg_strerror (err));
+          goto leave;
+        }
+
+      if (stat (fname, &sb))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
+          continue;
+        }
+      if (!S_ISDIR(sb.st_mode))
+        continue;
+
+      if (!add_to_strlist_try (&list, fname))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("add_to_strlist failed in %s: %s\n",
+                     __func__, gpg_strerror (err));
+          goto leave;
+        }
+    }
+  err = 0;
+  *r_list = list;
+  list = NULL;
+
+ leave:
+  free_strlist (list);
+  if (dir)
+    closedir (dir);
+  xfree (fname);
+  return err;
+}
+
+
+\f
+static gpg_error_t
+expire_one_domain (const char *top_dirname, const char *domain)
+{
+  gpg_error_t err;
+  char *dirname;
+  char *fname = NULL;
+  DIR *dir = NULL;
+  struct dirent *dentry;
+  struct stat sb;
+  time_t now = gnupg_get_time ();
+
+  dirname = make_filename_try (top_dirname, "pending", NULL);
+  if (!dirname)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("make_filename failed in %s: %s\n",
+                 __func__, gpg_strerror (err));
+      goto leave;
+    }
+
+  dir = opendir (dirname);
+  if (!dir)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (("can't access directory '%s': %s\n"),
+                 dirname, gpg_strerror (err));
+      goto leave;
+    }
+
+  while ((dentry = readdir (dir)))
+    {
+      if (*dentry->d_name == '.')
+        continue;
+      xfree (fname);
+      fname = make_filename_try (dirname, dentry->d_name, NULL);
+      if (!fname)
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("make_filename failed in %s: %s\n",
+                     __func__, gpg_strerror (err));
+          goto leave;
+        }
+      if (strlen (dentry->d_name) != 32)
+        {
+          log_info ("garbage file '%s' ignored\n", fname);
+          continue;
+        }
+      if (stat (fname, &sb))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error accessing '%s': %s\n", fname, gpg_strerror (err));
+          continue;
+        }
+      if (S_ISDIR(sb.st_mode))
+        {
+          log_info ("garbage directory '%s' ignored\n", fname);
+          continue;
+        }
+      if (sb.st_mtime + PENDING_TTL < now)
+        {
+          if (opt.verbose)
+            log_info ("domain %s: removing pending key '%s'\n",
+                      domain, dentry->d_name);
+          if (remove (fname))
+            {
+              err = gpg_error_from_syserror ();
+              /* In case the file has just been renamed or another
+               * processes is cleaning up, we don't print a diagnostic
+               * for ENOENT.  */
+              if (gpg_err_code (err) != GPG_ERR_ENOENT)
+                log_error ("error removing '%s': %s\n",
+                           fname, gpg_strerror (err));
+            }
+        }
+    }
+  err = 0;
+
+ leave:
+  if (dir)
+    closedir (dir);
+  xfree (dirname);
+  xfree (fname);
+  return err;
+
+}
+
+
+/* Scan spool directories and expire too old pending keys.  */
+static gpg_error_t
+expire_pending_confirmations (strlist_t domaindirs)
+{
+  gpg_error_t err = 0;
+  strlist_t sl;
+  const char *domain;
+
+  for (sl = domaindirs; sl; sl = sl->next)
+    {
+      domain = strrchr (sl->d, '/');
+      log_assert (domain);
+      domain++;
+
+      expire_one_domain (sl->d, domain);
+    }
+
+  return err;
+}
+
+
+/* List all configured domains.  */
+static gpg_error_t
+command_list_domains (void)
+{
+  static struct {
+    const char *name;
+    const char *perm;
+  } requireddirs[] = {
+    { "pending", "-rwx" },
+    { "hu",      "-rwxr-xr-x" }
+  };
+
+  gpg_error_t err;
+  strlist_t domaindirs;
+  strlist_t sl;
+  const char *domain;
+  char *fname = NULL;
+  int i;
+
+  err = get_domain_list (&domaindirs);
+  if (err)
+    {
+      log_error ("error reading list of domains: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  for (sl = domaindirs; sl; sl = sl->next)
+    {
+      domain = strrchr (sl->d, '/');
+      log_assert (domain);
+      domain++;
+      es_printf ("%s\n", domain);
+
+      /* Check that the required directories are there.  */
+      for (i=0; i < DIM (requireddirs); i++)
+        {
+          xfree (fname);
+          fname = make_filename_try (sl->d, requireddirs[i].name, NULL);
+          if (!fname)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          if (access (fname, W_OK))
+            {
+              err = gpg_error_from_syserror ();
+              if (gpg_err_code (err) == GPG_ERR_ENOENT)
+                {
+                  if (gnupg_mkdir (fname, requireddirs[i].perm))
+                    {
+                      err = gpg_error_from_syserror ();
+                      log_error ("domain %s: error creating subdir '%s': %s\n",
+                                 domain, requireddirs[i].name,
+                                 gpg_strerror (err));
+                    }
+                  else
+                    log_info ("domain %s: subdir '%s' created\n",
+                              domain, requireddirs[i].name);
+                }
+              else if (err)
+                log_error ("domain %s: problem with subdir '%s': %s\n",
+                           domain, requireddirs[i].name, gpg_strerror (err));
+            }
+        }
+
+      /* Print a warning if the sumbission address is not configured.  */
+      xfree (fname);
+      fname = make_filename_try (sl->d, "submission-address", NULL);
+      if (!fname)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      if (access (fname, F_OK))
+        {
+          err = gpg_error_from_syserror ();
+          if (gpg_err_code (err) == GPG_ERR_ENOENT)
+            log_error ("domain %s: submission address not configured\n",
+                       domain);
+          else
+            log_error ("domain %s: problem with '%s': %s\n",
+                       domain, fname, gpg_strerror (err));
+        }
+    }
+  err = 0;
+
+ leave:
+  xfree (fname);
+  free_strlist (domaindirs);
+  return err;
+}
+
+
+/* Run regular maintenance jobs.  */
+static gpg_error_t
+command_cron (void)
+{
+  gpg_error_t err;
+  strlist_t domaindirs;
+
+  err = get_domain_list (&domaindirs);
+  if (err)
+    {
+      log_error ("error reading list of domains: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  err = expire_pending_confirmations (domaindirs);
+
+  free_strlist (domaindirs);
+  return err;
+}
diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h
new file mode 100644 (file)
index 0000000..be85eec
--- /dev/null
@@ -0,0 +1,61 @@
+/* gpg-wks.h - Common definitions for wks server and client.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_GPG_WKS_H
+#define GNUPG_GPG_WKS_H
+
+#include "../common/util.h"
+#include "../common/strlist.h"
+#include "mime-maker.h"
+
+/* We keep all global options in the structure OPT.  */
+struct
+{
+  int verbose;
+  unsigned int debug;
+  int quiet;
+  int use_sendmail;
+  const char *output;
+  const char *gpg_program;
+  const char *directory;
+  const char *default_from;
+  strlist_t extra_headers;
+} opt;
+
+/* Debug values and macros.  */
+#define DBG_CRYPTO_VALUE      4        /* Debug low level crypto.  */
+#define DBG_MEMORY_VALUE     32        /* Debug memory allocation stuff.  */
+#define DBG_MEMSTAT_VALUE   128        /* Show memory statistics.  */
+#define DBG_IPC_VALUE      1024 /* Debug assuan communication.  */
+#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
+
+
+/*-- wks-util.c --*/
+gpg_error_t wks_send_mime (mime_maker_t mime);
+
+/*-- wks-receive.c --*/
+gpg_error_t wks_receive (estream_t fp,
+                         gpg_error_t (*result_cb)(void *opaque,
+                                                  const char *mediatype,
+                                                  estream_t data),
+                         void *cb_data);
+
+
+
+#endif /*GNUPG_GPG_WKS_H*/
index 2b177e2..ad61511 100644 (file)
@@ -147,6 +147,64 @@ get_outfp (estream_t *fp)
 }
 
 
+static void
+list_dirs (estream_t fp, char **names)
+{
+  static struct {
+    const char *name;
+    const char *(*fnc)(void);
+    const char *extra;
+    int special;
+  } list[] = {
+    { "sysconfdir",         gnupg_sysconfdir, NULL },
+    { "bindir",             gnupg_bindir,     NULL },
+    { "libexecdir",         gnupg_libexecdir, NULL },
+    { "libdir",             gnupg_libdir,     NULL },
+    { "datadir",            gnupg_datadir,    NULL },
+    { "localedir",          gnupg_localedir,  NULL },
+    { "dirmngr-socket",     dirmngr_user_socket_name, NULL, 1 },
+    { "dirmngr-socket",     dirmngr_sys_socket_name,  NULL, 2 },
+    { "dirmngr-sys-socket", dirmngr_sys_socket_name,  NULL, 1 },
+    { "agent-ssh-socket",   gnupg_socketdir,  GPG_AGENT_SSH_SOCK_NAME },
+    { "agent-socket",       gnupg_socketdir,  GPG_AGENT_SOCK_NAME },
+    { "homedir",            gnupg_homedir,    NULL }
+  };
+  int idx, j;
+  char *tmp;
+  const char *s;
+
+
+  for (idx = 0; idx < DIM (list); idx++)
+    {
+      if (list[idx].special == 1 && dirmngr_user_socket_name ())
+        ;
+      else if (list[idx].special == 2 && !dirmngr_user_socket_name ())
+        ;
+      else if (list[idx].special == 1 || list[idx].special == 2)
+        continue;
+
+      s = list[idx].fnc ();
+      if (list[idx].extra)
+        {
+          tmp = make_filename (s, list[idx].extra, NULL);
+          s = tmp;
+        }
+      else
+        tmp = NULL;
+      if (!names)
+        es_fprintf (fp, "%s:%s\n", list[idx].name, gc_percent_escape (s));
+      else
+        {
+          for (j=0; names[j]; j++)
+            if (!strcmp (names[j], list[idx].name))
+              es_fprintf (fp, "%s\n", s);
+        }
+
+      xfree (tmp);
+    }
+}
+
+
 /* gpgconf main. */
 int
 main (int argc, char **argv)
@@ -357,43 +415,7 @@ main (int argc, char **argv)
     case aListDirs:
       /* Show the system configuration directories for gpgconf.  */
       get_outfp (&outfp);
-      es_fprintf (outfp, "sysconfdir:%s\n",
-                  gc_percent_escape (gnupg_sysconfdir ()));
-      es_fprintf (outfp, "bindir:%s\n",
-                  gc_percent_escape (gnupg_bindir ()));
-      es_fprintf (outfp, "libexecdir:%s\n",
-                  gc_percent_escape (gnupg_libexecdir ()));
-      es_fprintf (outfp, "libdir:%s\n",
-                  gc_percent_escape (gnupg_libdir ()));
-      es_fprintf (outfp, "datadir:%s\n",
-                  gc_percent_escape (gnupg_datadir ()));
-      es_fprintf (outfp, "localedir:%s\n",
-                  gc_percent_escape (gnupg_localedir ()));
-
-      if (dirmngr_user_socket_name ())
-        {
-          es_fprintf (outfp, "dirmngr-socket:%s\n",
-                      gc_percent_escape (dirmngr_user_socket_name ()));
-          es_fprintf (outfp, "dirmngr-sys-socket:%s\n",
-                      gc_percent_escape (dirmngr_sys_socket_name ()));
-        }
-      else
-        {
-          es_fprintf (outfp, "dirmngr-socket:%s\n",
-                      gc_percent_escape (dirmngr_sys_socket_name ()));
-        }
-
-      {
-        char *tmp = make_filename (gnupg_socketdir (),
-                                   GPG_AGENT_SOCK_NAME, NULL);
-        es_fprintf (outfp, "agent-socket:%s\n", gc_percent_escape (tmp));
-        xfree (tmp);
-      }
-      {
-        char *tmp = xstrdup (gnupg_homedir ());
-        es_fprintf (outfp, "homedir:%s\n", gc_percent_escape (tmp));
-        xfree (tmp);
-      }
+      list_dirs (outfp, argc? argv : NULL);
       break;
 
     case aCreateSocketDir:
index 866215b..cee609c 100644 (file)
@@ -282,7 +282,7 @@ gpgtar_extract (const char *filename, int decrypt)
   if (filename)
     {
       if (!strcmp (filename, "-"))
-        stream = es_stdout;
+        stream = es_stdin;
       else
         stream = es_fopen (filename, "rb");
       if (!stream)
index 1d59d9c..cb2e700 100644 (file)
@@ -282,7 +282,7 @@ gpgtar_list (const char *filename, int decrypt)
   if (filename)
     {
       if (!strcmp (filename, "-"))
-        stream = es_stdout;
+        stream = es_stdin;
       else
         stream = es_fopen (filename, "rb");
       if (!stream)
index 416f514..fcbee50 100644 (file)
@@ -48,6 +48,8 @@
 enum cmd_and_opt_values
   {
     aNull = 0,
+    aCreate = 600,
+    aExtract,
     aEncrypt    = 'e',
     aDecrypt    = 'd',
     aSign       = 's',
@@ -84,8 +86,10 @@ enum cmd_and_opt_values
 static ARGPARSE_OPTS opts[] = {
   ARGPARSE_group (300, N_("@Commands:\n ")),
 
-  ARGPARSE_c (aEncrypt,   "encrypt", N_("create an archive")),
-  ARGPARSE_c (aDecrypt,   "decrypt", N_("extract an archive")),
+  ARGPARSE_c (aCreate,    "create",  N_("create an archive")),
+  ARGPARSE_c (aExtract,   "extract", N_("extract an archive")),
+  ARGPARSE_c (aEncrypt,   "encrypt", N_("create an encrypted archive")),
+  ARGPARSE_c (aDecrypt,   "decrypt", N_("extract an encrypted archive")),
   ARGPARSE_c (aSign,      "sign",    N_("create a signed archive")),
   ARGPARSE_c (aList,      "list-archive", N_("list an archive")),
 
@@ -275,7 +279,12 @@ shell_parse_argv (const char *s, int *r_argc, char ***r_argv)
     return 1;
 
   for (i = 0; list; i++)
-    (*r_argv)[i] = list->d, list = list->next;
+    {
+      gpgrt_annotate_leaked_object (list);
+      (*r_argv)[i] = list->d;
+      list = list->next;
+    }
+  gpgrt_annotate_leaked_object (*r_argv);
   return 0;
 }
 \f
@@ -312,6 +321,16 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
           set_cmd (&cmd, pargs->r_opt);
          break;
 
+        case aCreate:
+          set_cmd (&cmd, aEncrypt);
+          skip_crypto = 1;
+          break;
+
+        case aExtract:
+          set_cmd (&cmd, aDecrypt);
+          skip_crypto = 1;
+          break;
+
         case oRecipient:
           add_to_strlist (&opt.recipients, pargs->r.ret_str);
           break;
diff --git a/tools/mime-maker.c b/tools/mime-maker.c
new file mode 100644 (file)
index 0000000..fa42043
--- /dev/null
@@ -0,0 +1,667 @@
+/* mime-maker.c - Create MIME structures
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "zb32.h"
+#include "mime-maker.h"
+
+
+/* All valid charachters in a header name.  */
+#define HEADER_NAME_CHARS  ("abcdefghijklmnopqrstuvwxyz" \
+                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+                            "-01234567890")
+
+/* An object to store an header.  Also used for a list of headers.  */
+struct header_s
+{
+  struct header_s *next;
+  char *value;   /* Malloced value.  */
+  char name[1]; /* Name.  */
+};
+typedef struct header_s *header_t;
+
+
+/* An object to store a MIME part.  A part is the header plus the
+ * content (body). */
+struct part_s
+{
+  struct part_s *next;  /* Next part in the current container.  */
+  struct part_s *child; /* Child container.  */
+  char *mediatype;      /* Mediatype of the container (malloced). */
+  char *boundary;       /* Malloced boundary string.  */
+  header_t headers;     /* List of headers.  */
+  header_t *headers_tail;/* Address of last header in chain.  */
+  size_t bodylen;       /* Length of BODY.   */
+  char *body;           /* Malloced buffer with the body.  This is the
+                         * non-encoded value.  */
+};
+typedef struct part_s *part_t;
+
+
+
+/* Definition of the mime parser object.  */
+struct mime_maker_context_s
+{
+  void *cookie;                /* Cookie passed to all callbacks.  */
+
+  unsigned int verbose:1;      /* Enable verbose mode.  */
+  unsigned int debug:1;        /* Enable debug mode.  */
+
+  part_t mail;                 /* The MIME tree.  */
+  part_t current_part;
+
+  int boundary_counter;  /* Used to create easy to read boundaries.  */
+  char *boundary_suffix; /* Random string used in the boundaries.  */
+
+  struct b64state *b64state;     /* NULL or malloced Base64 decoder state.  */
+
+  /* Helper to convey the output stream to recursive functions. */
+  estream_t outfp;
+};
+
+
+/* Create a new mime make object.  COOKIE is a values woich will be
+ * used as first argument for all callbacks registered with this
+ * object.  */
+gpg_error_t
+mime_maker_new (mime_maker_t *r_maker, void *cookie)
+{
+  mime_maker_t ctx;
+
+  *r_maker = NULL;
+
+  ctx = xtrycalloc (1, sizeof *ctx);
+  if (!ctx)
+    return gpg_error_from_syserror ();
+  ctx->cookie = cookie;
+
+  *r_maker = ctx;
+  return 0;
+}
+
+
+static void
+release_parts (part_t part)
+{
+  while (part)
+    {
+      part_t partnext = part->next;
+      while (part->headers)
+        {
+          header_t hdrnext = part->headers->next;
+          xfree (part->headers);
+          part->headers = hdrnext;
+        }
+      release_parts (part->child);
+      xfree (part->mediatype);
+      xfree (part->boundary);
+      xfree (part->body);
+      xfree (part);
+      part = partnext;
+    }
+}
+
+
+/* Release a mime maker object.  */
+void
+mime_maker_release (mime_maker_t ctx)
+{
+  if (!ctx)
+    return;
+
+  release_parts (ctx->mail);
+  xfree (ctx->boundary_suffix);
+  xfree (ctx);
+}
+
+
+/* Set verbose and debug mode.  */
+void
+mime_maker_set_verbose (mime_maker_t ctx, int level)
+{
+  if (!level)
+    {
+      ctx->verbose = 0;
+      ctx->debug = 0;
+    }
+  else
+    {
+      ctx->verbose = 1;
+      if (level > 10)
+        ctx->debug = 1;
+    }
+}
+
+
+static void
+dump_parts (part_t part, int level)
+{
+  header_t hdr;
+
+  for (; part; part = part->next)
+    {
+      log_debug ("%*s[part]\n", level*2, "");
+      for (hdr = part->headers; hdr; hdr = hdr->next)
+        {
+          log_debug ("%*s%s: %s\n", level*2, "", hdr->name, hdr->value);
+        }
+      log_debug ("%*s[body %zu bytes]\n", level*2, "", part->bodylen);
+      if (part->child)
+        {
+          log_debug ("%*s[container]\n", level*2, "");
+          dump_parts (part->child, level+1);
+        }
+    }
+}
+
+
+/* Dump the mime tree for debugging.  */
+void
+mime_maker_dump_tree (mime_maker_t ctx)
+{
+  dump_parts (ctx->mail, 0);
+}
+
+
+/* Find the parent node for NEEDLE starting at ROOT.  */
+static part_t
+find_parent (part_t root, part_t needle)
+{
+  part_t node, n;
+
+  for (node = root->child; node; node = node->next)
+    {
+      if (node == needle)
+        return root;
+      if ((n = find_parent (node, needle)))
+        return n;
+    }
+  return NULL;
+}
+
+
+/* Create a boundary string.  Outr codes is aware of the general
+ * structure of that string (gebins with "=-=") so that
+ * it can protect against accidently used boundaries within the
+ * content.   */
+static char *
+generate_boundary (mime_maker_t ctx)
+{
+  if (!ctx->boundary_suffix)
+    {
+      char buffer[12];
+
+      gcry_create_nonce (buffer, sizeof buffer);
+      ctx->boundary_suffix = zb32_encode (buffer, 8 * sizeof buffer);
+      if (!ctx->boundary_suffix)
+        return NULL;
+    }
+
+  ctx->boundary_counter++;
+  return es_bsprintf ("=-=%02d-%s=-=",
+                      ctx->boundary_counter, ctx->boundary_suffix);
+}
+
+
+/* Ensure that the context has a MAIL and CURRENT_PART object and
+ * return the parent object if available  */
+static gpg_error_t
+ensure_part (mime_maker_t ctx, part_t *r_parent)
+{
+  if (!ctx->mail)
+    {
+      ctx->mail = xtrycalloc (1, sizeof *ctx->mail);
+      if (!ctx->mail)
+        return gpg_error_from_syserror ();
+      log_assert (!ctx->current_part);
+      ctx->current_part = ctx->mail;
+      ctx->current_part->headers_tail = &ctx->current_part->headers;
+    }
+  log_assert (ctx->current_part);
+  if (r_parent)
+    *r_parent = find_parent (ctx->mail, ctx->current_part);
+
+  return 0;
+}
+
+
+/* Transform a header name into a standard capitalized format.
+ * "Content-Type".  Conversion stops at the colon. */
+static void
+capitalize_header_name (char *name)
+{
+  unsigned char *p = name;
+  int first = 1;
+
+  /* Special cases first.  */
+  if (!ascii_strcasecmp (name, "MIME-Version"))
+    {
+      strcpy (name, "MIME-Version");
+      return;
+    }
+
+  /* Regular cases.  */
+  for (; *p && *p != ':'; p++)
+    {
+      if (*p == '-')
+        first = 1;
+      else if (first)
+        {
+          if (*p >= 'a' && *p <= 'z')
+            *p = *p - 'a' + 'A';
+          first = 0;
+        }
+      else if (*p >= 'A' && *p <= 'Z')
+        *p = *p - 'A' + 'a';
+    }
+}
+
+
+/* Check whether a header with NAME has already been set into PART.
+ * NAME must be in canonical capitalized format.  Return true or
+ * false. */
+static int
+have_header (part_t part, const char *name)
+{
+  header_t hdr;
+
+  for (hdr = part->headers; hdr; hdr = hdr->next)
+    if (!strcmp (hdr->name, name))
+      return 1;
+  return 0;
+}
+
+
+/* Helper to add a header to a part.  */
+static gpg_error_t
+add_header (part_t part, const char *name, const char *value)
+{
+  gpg_error_t err;
+  header_t hdr;
+  size_t namelen;
+  const char *s;
+
+  if (!value)
+    {
+      s = strchr (name, '=');
+      if (!s)
+        return gpg_error (GPG_ERR_INV_ARG);
+      namelen = s - name;
+      value = s+1;
+    }
+  else
+    namelen = strlen (name);
+
+  hdr = xtrymalloc (sizeof *hdr + namelen);
+  if (!hdr)
+    return gpg_error_from_syserror ();
+  hdr->next = NULL;
+  memcpy (hdr->name, name, namelen);
+  hdr->name[namelen] = 0;
+
+  /* Check that the header name is valid.  We allow all lower and
+   * uppercase letters and, except for the first character, digits and
+   * the dash.  */
+  if (strspn (hdr->name, HEADER_NAME_CHARS) != namelen
+      || strchr ("-0123456789", *hdr->name))
+    {
+      xfree (hdr);
+      return gpg_error (GPG_ERR_INV_NAME);
+    }
+
+  capitalize_header_name (hdr->name);
+  hdr->value = xtrystrdup (value);
+  if (!hdr->value)
+    {
+      err = gpg_error_from_syserror ();
+      xfree (hdr);
+      return err;
+    }
+
+  if (part)
+    {
+      *part->headers_tail = hdr;
+      part->headers_tail = &hdr->next;
+    }
+  else
+    xfree (hdr);
+
+  return 0;
+}
+
+
+/* Add a header with NAME and VALUE to the current mail.  A LF in the
+ * VALUE will be handled automagically.  If NULL is used for VALUE it
+ * is expected that the NAME has the format "NAME=VALUE" and VALUE is
+ * taken from there.
+ *
+ * If no container has been added, the header will be used for the
+ * regular mail headers and not for a MIME part.  If the current part
+ * is in a container and a body has been added, we append a new part
+ * to the current container.  Thus for a non-MIME mail the caller
+ * needs to call this function followed by a call to add a body.  When
+ * adding a Content-Type the boundary parameter must not be included.
+ */
+gpg_error_t
+mime_maker_add_header (mime_maker_t ctx, const char *name, const char *value)
+{
+  gpg_error_t err;
+  part_t part, parent;
+
+  /* Hack to use this fucntion for a synacx check of NAME and VALUE.  */
+  if (!ctx)
+    return add_header (NULL, name, value);
+
+  err = ensure_part (ctx, &parent);
+  if (err)
+    return err;
+  part = ctx->current_part;
+
+  if (part->body && !parent)
+    {
+      /* We already have a body but no parent.  Adding another part is
+       * thus not possible.  */
+      return gpg_error (GPG_ERR_CONFLICT);
+    }
+  if (part->body)
+    {
+      /* We already have a body and there is a parent.  We now append
+       * a new part to the current container.  */
+      part = xtrycalloc (1, sizeof *part);
+      if (!part)
+        return gpg_error_from_syserror ();
+      part->headers_tail = &part->headers;
+      log_assert (!ctx->current_part->next);
+      ctx->current_part->next = part;
+      ctx->current_part = part;
+    }
+
+  /* If no NAME and no VALUE has been given we do not add a header.
+   * This can be used to create a new part without any header.  */
+  if (!name && !value)
+    return 0;
+
+  /* If we add Content-Type, make sure that we have a MIME-version
+   * header first; this simply looks better.  */
+  if (!ascii_strcasecmp (name, "Content-Type")
+      && !have_header (ctx->mail, "MIME-Version"))
+    {
+      err = add_header (ctx->mail, "MIME-Version", "1.0");
+      if (err)
+        return err;
+    }
+  return add_header (part, name, value);
+}
+
+
+/* Helper for mime_maker_add_{body,stream}.  */
+static gpg_error_t
+add_body (mime_maker_t ctx, const void *data, size_t datalen)
+{
+  gpg_error_t err;
+  part_t part, parent;
+
+  err = ensure_part (ctx, &parent);
+  if (err)
+    return err;
+  part = ctx->current_part;
+  if (part->body)
+    return gpg_error (GPG_ERR_CONFLICT);
+
+  part->body = xtrymalloc (datalen? datalen : 1);
+  if (!part->body)
+    return gpg_error_from_syserror ();
+  part->bodylen = datalen;
+  if (data)
+    memcpy (part->body, data, datalen);
+
+  return 0;
+}
+
+
+/* Add STRING as body to the mail or the current MIME container.  A
+ * second call to this function is not allowed.
+ *
+ * FIXME: We may want to have an append_body to add more data to a body.
+ */
+gpg_error_t
+mime_maker_add_body (mime_maker_t ctx, const char *string)
+{
+  return add_body (ctx, string, strlen (string));
+}
+
+
+/* This is the same as mime_maker_add_body but takes a stream as
+ * argument.  As of now the stream is copied to the MIME object but
+ * eventually we may delay that and read the stream only at the time
+ * it is needed.  Note that the address of the stream object must be
+ * passed and that the ownership of the stream is transferred to this
+ * MIME object.  To indicate the latter the function will store NULL
+ * at the ADDR_STREAM so that a caller can't use that object anymore
+ * except for es_fclose which accepts a NULL pointer.  */
+gpg_error_t
+mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr)
+{
+  void *data;
+  size_t datalen;
+
+  es_rewind (*stream_addr);
+  if (es_fclose_snatch (*stream_addr, &data, &datalen))
+    return gpg_error_from_syserror ();
+  *stream_addr = NULL;
+  return add_body (ctx, data, datalen);
+}
+
+
+/* Add a new MIME container.  The caller needs to provide the media
+ * and media-subtype in MEDIATYPE.  If MEDIATYPE is NULL
+ * "multipart/mixed" is assumed.  This function will then add a
+ * Content-Type header with that media type and an approriate boundary
+ * string to the parent part.  */
+gpg_error_t
+mime_maker_add_container (mime_maker_t ctx, const char *mediatype)
+{
+  gpg_error_t err;
+  part_t part;
+
+  if (!mediatype)
+    mediatype = "multipart/mixed";
+
+  err = ensure_part (ctx, NULL);
+  if (err)
+    return err;
+  part = ctx->current_part;
+  if (part->body)
+    return gpg_error (GPG_ERR_CONFLICT); /* There is already a body. */
+  if (part->child || part->mediatype || part->boundary)
+    return gpg_error (GPG_ERR_CONFLICT); /* There is already a container. */
+
+  /* If a content type has not yet been set, do it now.  The boundary
+   * will be added while writing the headers.  */
+  if (!have_header (ctx->mail, "Content-Type"))
+    {
+      err = add_header (ctx->mail, "Content-Type", mediatype);
+      if (err)
+        return err;
+    }
+
+  /* Create a child node.  */
+  part->child = xtrycalloc (1, sizeof *part->child);
+  if (!part->child)
+    return gpg_error_from_syserror ();
+  part->child->headers_tail = &part->child->headers;
+
+  part->mediatype = xtrystrdup (mediatype);
+  if (!part->mediatype)
+    {
+      err = gpg_error_from_syserror ();
+      xfree (part->child);
+      part->child = NULL;
+      return err;
+    }
+
+  part->boundary = generate_boundary (ctx);
+  if (!part->boundary)
+    {
+      err = gpg_error_from_syserror ();
+      xfree (part->child);
+      part->child = NULL;
+      xfree (part->mediatype);
+      part->mediatype = NULL;
+      return err;
+    }
+
+  part = part->child;
+  ctx->current_part = part;
+
+  return 0;
+}
+
+
+/* Write the Content-Type header with the boundary value.  */
+static gpg_error_t
+write_ct_with_boundary (mime_maker_t ctx,
+                        const char *value, const char *boundary)
+{
+  const char *s;
+
+  if (!*value)
+    return gpg_error (GPG_ERR_INV_VALUE);  /* Empty string.  */
+
+  for (s=value + strlen (value) - 1;
+       (s >= value
+        && (*s == ' ' || *s == '\t' || *s == '\n'));
+       s--)
+    ;
+  if (!(s >= value))
+    return gpg_error (GPG_ERR_INV_VALUE);  /* Only spaces.  */
+
+  /* Fixme: We should use a dedicated header write functions which
+   * properly wraps the header.  */
+  es_fprintf (ctx->outfp, "Content-Type: %s%s\n\tboundary=\"%s\"\n",
+              value,
+              (*s == ';')? "":";",
+              boundary);
+  return 0;
+}
+
+
+/* Recursive worker for mime_maker_make.  */
+static gpg_error_t
+write_tree (mime_maker_t ctx, part_t parent, part_t part)
+{
+  gpg_error_t err;
+  header_t hdr;
+
+  for (; part; part = part->next)
+    {
+      for (hdr = part->headers; hdr; hdr = hdr->next)
+        {
+          if (part->child && !strcmp (hdr->name, "Content-Type"))
+            write_ct_with_boundary (ctx, hdr->value, part->boundary);
+          else
+            es_fprintf (ctx->outfp, "%s: %s\n", hdr->name, hdr->value);
+        }
+      es_fputc ('\n', ctx->outfp);
+      if (part->body)
+        {
+          if (es_write (ctx->outfp, part->body, part->bodylen, NULL))
+            return gpg_error_from_syserror ();
+        }
+      if (part->child)
+        {
+          log_assert (part->boundary);
+          if (es_fprintf (ctx->outfp, "\n--%s\n", part->boundary) < 0)
+            return gpg_error_from_syserror ();
+          err = write_tree (ctx, part, part->child);
+          if (err)
+            return err;
+          if (es_fprintf (ctx->outfp, "\n--%s--\n", part->boundary) < 0)
+            return gpg_error_from_syserror ();
+        }
+
+      if (part->next)
+        {
+          log_assert (parent && parent->boundary);
+          if (es_fprintf (ctx->outfp, "\n--%s\n", parent->boundary) < 0)
+            return gpg_error_from_syserror ();
+        }
+    }
+  return 0;
+}
+
+
+/* Add headers we always require.  */
+static gpg_error_t
+add_missing_headers (mime_maker_t ctx)
+{
+  gpg_error_t err;
+
+  if (!ctx->mail)
+    return gpg_error (GPG_ERR_NO_DATA);
+  if (!have_header (ctx->mail, "MIME-Version"))
+    {
+      /* Even if a Content-Type has never been set, we want to
+       * announce that we do MIME.  */
+      err = add_header (ctx->mail, "MIME-Version", "1.0");
+      if (err)
+        goto leave;
+    }
+
+  if (!have_header (ctx->mail, "Date"))
+    {
+      char *p = rfctimestamp (make_timestamp ());
+      if (!p)
+        err = gpg_error_from_syserror ();
+      else
+        err = add_header (ctx->mail, "Date", p);
+      xfree (p);
+      if (err)
+        goto leave;
+    }
+
+
+ leave:
+  return err;
+}
+
+
+/* Create message from the tree MIME and write it to FP.  Noet that
+ * the output uses only a LF and a later called sendmail(1) is
+ * expected to convert them to network line endings.  */
+gpg_error_t
+mime_maker_make (mime_maker_t ctx, estream_t fp)
+{
+  gpg_error_t err;
+
+  err = add_missing_headers (ctx);
+  if (err)
+    return err;
+
+  ctx->outfp = fp;
+  err = write_tree (ctx, NULL, ctx->mail);
+
+  ctx->outfp = NULL;
+  return err;
+}
diff --git a/tools/mime-maker.h b/tools/mime-maker.h
new file mode 100644 (file)
index 0000000..b21f7dd
--- /dev/null
@@ -0,0 +1,43 @@
+/* mime-maker.h - Create MIME structures
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_MIME_MAKER_H
+#define GNUPG_MIME_MAKER_H
+
+struct mime_maker_context_s;
+typedef struct mime_maker_context_s *mime_maker_t;
+
+gpg_error_t mime_maker_new (mime_maker_t *r_ctx, void *cookie);
+void        mime_maker_release (mime_maker_t ctx);
+
+void mime_maker_set_verbose (mime_maker_t ctx, int level);
+
+void mime_maker_dump_tree (mime_maker_t ctx);
+
+gpg_error_t mime_maker_add_header (mime_maker_t ctx,
+                                   const char *name, const char *value);
+gpg_error_t mime_maker_add_body (mime_maker_t ctx, const char *string);
+gpg_error_t mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr);
+gpg_error_t mime_maker_add_container (mime_maker_t ctx, const char *mediatype);
+
+gpg_error_t mime_maker_make (mime_maker_t ctx, estream_t fp);
+
+
+
+#endif /*GNUPG_MIME_MAKER_H*/
diff --git a/tools/mime-parser.c b/tools/mime-parser.c
new file mode 100644 (file)
index 0000000..5f3659e
--- /dev/null
@@ -0,0 +1,772 @@
+/* mime-parser.c - Parse MIME structures (high level rfc822 parser).
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "rfc822parse.h"
+#include "mime-parser.h"
+
+
+enum pgpmime_states
+  {
+    PGPMIME_NONE = 0,
+    PGPMIME_WAIT_ENCVERSION,
+    PGPMIME_IN_ENCVERSION,
+    PGPMIME_WAIT_ENCDATA,
+    PGPMIME_IN_ENCDATA,
+    PGPMIME_GOT_ENCDATA,
+    PGPMIME_WAIT_SIGNEDDATA,
+    PGPMIME_IN_SIGNEDDATA,
+    PGPMIME_WAIT_SIGNATURE,
+    PGPMIME_IN_SIGNATURE,
+    PGPMIME_GOT_SIGNATURE,
+    PGPMIME_INVALID
+  };
+
+
+/* Definition of the mime parser object.  */
+struct mime_parser_context_s
+{
+  void *cookie;                /* Cookie passed to all callbacks.  */
+
+  /* The callback to announce a new part.  */
+  gpg_error_t (*new_part) (void *cookie,
+                           const char *mediatype,
+                           const char *mediasubtype);
+  /* The callback to return data of a part.  */
+  gpg_error_t (*part_data) (void *cookie,
+                            const void *data,
+                            size_t datalen);
+  /* The callback to collect encrypted data.  */
+  gpg_error_t (*collect_encrypted) (void *cookie, const char *data);
+  /* The callback to collect signed data.  */
+  gpg_error_t (*collect_signeddata) (void *cookie, const char *data);
+  /* The callback to collect a signature.  */
+  gpg_error_t (*collect_signature) (void *cookie, const char *data);
+
+  /* Helper to convey error codes from user callbacks.  */
+  gpg_error_t err;
+
+  int nesting_level;           /* The current nesting level.  */
+  int hashing_at_level;        /* The nesting level at which we are hashing. */
+  enum pgpmime_states pgpmime; /* Current PGP/MIME state.  */
+  unsigned int delay_hashing:1;/* Helper for PGPMIME_IN_SIGNEDDATA. */
+  unsigned int want_part:1;    /* Return the current part.  */
+  unsigned int decode_part:2;  /* Decode the part.  1 = QP, 2 = Base64. */
+
+  unsigned int verbose:1;      /* Enable verbose mode.  */
+  unsigned int debug:1;        /* Enable debug mode.  */
+
+  /* Flags to help with debug output.  */
+  struct {
+    unsigned int n_skip;         /* Skip showing these number of lines.  */
+    unsigned int header:1;       /* Show the header lines.  */
+    unsigned int data:1;         /* Show the data lines.  */
+    unsigned int as_note:1;      /* Show the next data line as a note.  */
+    unsigned int boundary : 1;
+  } show;
+
+  struct b64state *b64state;     /* NULL or malloced Base64 decoder state.  */
+
+  /* A buffer for reading a mail line,  */
+  char line[5000];
+};
+
+
+/* Print the event received by the parser for debugging.  */
+static void
+show_message_parser_event (rfc822parse_event_t event)
+{
+  const char *s;
+
+  switch (event)
+    {
+    case RFC822PARSE_OPEN: s= "Open"; break;
+    case RFC822PARSE_CLOSE: s= "Close"; break;
+    case RFC822PARSE_CANCEL: s= "Cancel"; break;
+    case RFC822PARSE_T2BODY: s= "T2Body"; break;
+    case RFC822PARSE_FINISH: s= "Finish"; break;
+    case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break;
+    case RFC822PARSE_LEVEL_DOWN: s= "Level_Down"; break;
+    case RFC822PARSE_LEVEL_UP: s= "Level_Up"; break;
+    case RFC822PARSE_BOUNDARY: s= "Boundary"; break;
+    case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break;
+    case RFC822PARSE_BEGIN_HEADER: s= "Begin_Header"; break;
+    case RFC822PARSE_PREAMBLE: s= "Preamble"; break;
+    case RFC822PARSE_EPILOGUE: s= "Epilogue"; break;
+    default: s= "[unknown event]"; break;
+    }
+  log_debug ("*** RFC822 event %s\n", s);
+}
+
+
+/* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
+   Returns the new length of the buffer and stores true at R_SLBRK if
+   the line ended with a soft line break; false is stored if not.
+   This fucntion asssumes that a complete line is passed in
+   buffer.  */
+static size_t
+qp_decode (char *buffer, size_t length, int *r_slbrk)
+{
+  char *d, *s;
+
+  if (r_slbrk)
+    *r_slbrk = 0;
+
+  /* Fixme:  We should remove trailing white space first.  */
+  for (s=d=buffer; length; length--)
+    {
+      if (*s == '=')
+        {
+          if (length > 2 && hexdigitp (s+1) && hexdigitp (s+2))
+            {
+              s++;
+              *(unsigned char*)d++ = xtoi_2 (s);
+              s += 2;
+              length -= 2;
+            }
+          else if (length > 2 && s[1] == '\r' && s[2] == '\n')
+            {
+              /* Soft line break.  */
+              s += 3;
+              length -= 2;
+              if (r_slbrk && length == 1)
+                *r_slbrk = 1;
+            }
+          else if (length > 1 && s[1] == '\n')
+            {
+              /* Soft line break with only a Unix line terminator. */
+              s += 2;
+              length -= 1;
+              if (r_slbrk && length == 1)
+                *r_slbrk = 1;
+            }
+          else if (length == 1)
+            {
+              /* Soft line break at the end of the line. */
+              s += 1;
+              if (r_slbrk)
+                *r_slbrk = 1;
+            }
+          else
+            *d++ = *s++;
+        }
+      else
+        *d++ = *s++;
+    }
+
+  return d - buffer;
+}
+
+
+/* This function is called by parse_mail to communicate events.  This
+ * callback communicates with the caller using a structure passed in
+ * OPAQUE.  Should return 0 on success or set ERRNO and return -1. */
+static int
+parse_message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
+{
+  mime_parser_t ctx = opaque;
+  const char *s;
+  int rc = 0;
+
+  if (ctx->debug)
+    show_message_parser_event (event);
+
+  if (event == RFC822PARSE_BEGIN_HEADER || event == RFC822PARSE_T2BODY)
+    {
+      /* We need to check here whether to start collecting signed data
+       * because attachments might come without header lines and thus
+       * we won't see the BEGIN_HEADER event.  */
+      if (ctx->pgpmime == PGPMIME_WAIT_SIGNEDDATA)
+        {
+          if (ctx->debug)
+            log_debug ("begin_hash\n");
+          ctx->hashing_at_level = ctx->nesting_level;
+          ctx->pgpmime = PGPMIME_IN_SIGNEDDATA;
+          ctx->delay_hashing = 0;
+        }
+    }
+
+  if (event == RFC822PARSE_OPEN)
+    {
+      /* Initialize for a new message. */
+      ctx->show.header = 1;
+    }
+  else if (event == RFC822PARSE_T2BODY)
+    {
+      rfc822parse_field_t field;
+
+      ctx->want_part = 0;
+      ctx->decode_part = 0;
+      field = rfc822parse_parse_field (msg, "Content-Type", -1);
+      if (field)
+        {
+          const char *s1, *s2;
+
+          s1 = rfc822parse_query_media_type (field, &s2);
+          if (s1)
+            {
+              if (ctx->verbose)
+                log_debug ("h media: %*s%s %s\n",
+                           ctx->nesting_level*2, "", s1, s2);
+              if (ctx->pgpmime == PGPMIME_WAIT_ENCVERSION)
+                {
+                  if (!strcmp (s1, "application")
+                      && !strcmp (s2, "pgp-encrypted"))
+                    {
+                      if (ctx->debug)
+                        log_debug ("c begin_encversion\n");
+                      ctx->pgpmime = PGPMIME_IN_ENCVERSION;
+                    }
+                  else
+                    {
+                      log_error ("invalid PGP/MIME structure;"
+                                 " expected '%s', got '%s/%s'\n",
+                                 "application/pgp-encrypted", s1, s2);
+                      ctx->pgpmime = PGPMIME_INVALID;
+                    }
+                }
+              else if (ctx->pgpmime == PGPMIME_WAIT_ENCDATA)
+                {
+                  if (!strcmp (s1, "application")
+                      && !strcmp (s2, "octet-stream"))
+                    {
+                      if (ctx->debug)
+                        log_debug ("c begin_encdata\n");
+                      ctx->pgpmime = PGPMIME_IN_ENCDATA;
+                    }
+                  else
+                    {
+                      log_error ("invalid PGP/MIME structure;"
+                                 " expected '%s', got '%s/%s'\n",
+                                 "application/octet-stream", s1, s2);
+                      ctx->pgpmime = PGPMIME_INVALID;
+                    }
+                }
+              else if (ctx->pgpmime == PGPMIME_WAIT_SIGNATURE)
+                {
+                  if (!strcmp (s1, "application")
+                      && !strcmp (s2, "pgp-signature"))
+                    {
+                      if (ctx->debug)
+                        log_debug ("c begin_signature\n");
+                      ctx->pgpmime = PGPMIME_IN_SIGNATURE;
+                    }
+                  else
+                    {
+                      log_error ("invalid PGP/MIME structure;"
+                                 " expected '%s', got '%s/%s'\n",
+                                 "application/pgp-signature", s1, s2);
+                      ctx->pgpmime = PGPMIME_INVALID;
+                    }
+                }
+              else if (!strcmp (s1, "multipart")
+                       && !strcmp (s2, "encrypted"))
+                {
+                  s = rfc822parse_query_parameter (field, "protocol", 0);
+                  if (s)
+                    {
+                      if (ctx->debug)
+                        log_debug ("h encrypted.protocol: %s\n", s);
+                      if (!strcmp (s, "application/pgp-encrypted"))
+                        {
+                          if (ctx->pgpmime)
+                            log_error ("note: "
+                                       "ignoring nested PGP/MIME signature\n");
+                          else
+                            ctx->pgpmime = PGPMIME_WAIT_ENCVERSION;
+                        }
+                      else if (ctx->verbose)
+                        log_debug ("# this protocol is not supported\n");
+                    }
+                }
+              else if (!strcmp (s1, "multipart")
+                       && !strcmp (s2, "signed"))
+                {
+                  s = rfc822parse_query_parameter (field, "protocol", 1);
+                  if (s)
+                    {
+                      if (ctx->debug)
+                        log_debug ("h signed.protocol: %s\n", s);
+                      if (!strcmp (s, "application/pgp-signature"))
+                        {
+                          if (ctx->pgpmime)
+                            log_error ("note: "
+                                       "ignoring nested PGP/MIME signature\n");
+                          else
+                            ctx->pgpmime = PGPMIME_WAIT_SIGNEDDATA;
+                        }
+                      else if (ctx->verbose)
+                        log_debug ("# this protocol is not supported\n");
+                    }
+                }
+              else if (ctx->new_part)
+                {
+                  ctx->err = ctx->new_part (ctx->cookie, s1, s2);
+                  if (!ctx->err)
+                    ctx->want_part = 1;
+                  else if (gpg_err_code (ctx->err) == GPG_ERR_FALSE)
+                    ctx->err = 0;
+                  else if (gpg_err_code (ctx->err) == GPG_ERR_TRUE)
+                    {
+                      ctx->want_part = ctx->decode_part = 1;
+                      ctx->err = 0;
+                    }
+                }
+            }
+          else
+            {
+              if (ctx->debug)
+                log_debug ("h media: %*s none\n", ctx->nesting_level*2, "");
+              if (ctx->new_part)
+                {
+                  ctx->err = ctx->new_part (ctx->cookie, "", "");
+                  if (!ctx->err)
+                    ctx->want_part = 1;
+                  else if (gpg_err_code (ctx->err) == GPG_ERR_FALSE)
+                    ctx->err = 0;
+                  else if (gpg_err_code (ctx->err) == GPG_ERR_TRUE)
+                    {
+                      ctx->want_part = ctx->decode_part = 1;
+                      ctx->err = 0;
+                    }
+                }
+            }
+
+          rfc822parse_release_field (field);
+        }
+      else
+        {
+          if (ctx->verbose)
+            log_debug ("h media: %*stext plain [assumed]\n",
+                       ctx->nesting_level*2, "");
+          if (ctx->new_part)
+            {
+              ctx->err = ctx->new_part (ctx->cookie, "text", "plain");
+              if (!ctx->err)
+                ctx->want_part = 1;
+              else if (gpg_err_code (ctx->err) == GPG_ERR_FALSE)
+                ctx->err = 0;
+              else if (gpg_err_code (ctx->err) == GPG_ERR_TRUE)
+                {
+                  ctx->want_part = ctx->decode_part = 1;
+                  ctx->err = 0;
+                }
+            }
+        }
+
+      /* Figure out the encoding if needed.  */
+      if (ctx->decode_part)
+        {
+          char *value;
+          size_t valueoff;
+
+          ctx->decode_part = 0; /* Fallback for unknown encoding.  */
+          value = rfc822parse_get_field (msg, "Content-Transfer-Encoding", -1,
+                                         &valueoff);
+          if (value)
+            {
+              if (!stricmp (value+valueoff, "quoted-printable"))
+                ctx->decode_part = 1;
+              else if (!stricmp (value+valueoff, "base64"))
+                {
+                  ctx->decode_part = 2;
+                  if (ctx->b64state)
+                    b64dec_finish (ctx->b64state); /* Reuse state.  */
+                  else
+                    {
+                      ctx->b64state = xtrymalloc (sizeof *ctx->b64state);
+                      if (!ctx->b64state)
+                        rc = gpg_error_from_syserror ();
+                    }
+                  if (!rc)
+                    rc = b64dec_start (ctx->b64state, NULL);
+                }
+              free (value); /* Right, we need a plain free.  */
+            }
+        }
+
+      ctx->show.header = 0;
+      ctx->show.data = 1;
+      ctx->show.n_skip = 1;
+    }
+  else if (event == RFC822PARSE_PREAMBLE)
+    ctx->show.as_note = 1;
+  else if (event == RFC822PARSE_LEVEL_DOWN)
+    {
+      if (ctx->debug)
+        log_debug ("b down\n");
+      ctx->nesting_level++;
+    }
+  else if (event == RFC822PARSE_LEVEL_UP)
+    {
+      if (ctx->debug)
+        log_debug ("b up\n");
+      if (ctx->nesting_level)
+        ctx->nesting_level--;
+      else
+        log_error ("invalid structure (bad nesting level)\n");
+    }
+  else if (event == RFC822PARSE_BOUNDARY || event == RFC822PARSE_LAST_BOUNDARY)
+    {
+      ctx->show.data = 0;
+      ctx->show.boundary = 1;
+      if (event == RFC822PARSE_BOUNDARY)
+        {
+          ctx->show.header = 1;
+          ctx->show.n_skip = 1;
+          if (ctx->debug)
+            log_debug ("b part\n");
+        }
+      else if (ctx->debug)
+        log_debug ("b last\n");
+
+      if (ctx->pgpmime == PGPMIME_IN_ENCDATA)
+        {
+          if (ctx->debug)
+            log_debug ("c end_encdata\n");
+          ctx->pgpmime = PGPMIME_GOT_ENCDATA;
+          /* FIXME: We should assert (event == LAST_BOUNDARY).  */
+        }
+      else if (ctx->pgpmime == PGPMIME_IN_SIGNEDDATA
+               && ctx->nesting_level == ctx->hashing_at_level)
+        {
+          if (ctx->debug)
+            log_debug ("c end_hash\n");
+          ctx->pgpmime = PGPMIME_WAIT_SIGNATURE;
+          if (ctx->collect_signeddata)
+            ctx->err = ctx->collect_signeddata (ctx->cookie, NULL);
+        }
+      else if (ctx->pgpmime == PGPMIME_IN_SIGNATURE)
+        {
+          if (ctx->debug)
+            log_debug ("c end_signature\n");
+          ctx->pgpmime = PGPMIME_GOT_SIGNATURE;
+          /* FIXME: We should assert (event == LAST_BOUNDARY).  */
+        }
+      else if (ctx->want_part)
+        {
+          if (ctx->part_data)
+            {
+              /* FIXME: We may need to flush things.  */
+              ctx->err = ctx->part_data (ctx->cookie, NULL, 0);
+            }
+          ctx->want_part = 0;
+        }
+    }
+
+  return rc;
+}
+
+
+/* Create a new mime parser object.  COOKIE is a values which will be
+ * used as first argument for all callbacks registered with this
+ * parser object.  */
+gpg_error_t
+mime_parser_new (mime_parser_t *r_parser, void *cookie)
+{
+  mime_parser_t ctx;
+
+  *r_parser = NULL;
+
+  ctx = xtrycalloc (1, sizeof *ctx);
+  if (!ctx)
+    return gpg_error_from_syserror ();
+  ctx->cookie = cookie;
+
+  *r_parser = ctx;
+  return 0;
+}
+
+
+/* Release a mime parser object.  */
+void
+mime_parser_release (mime_parser_t ctx)
+{
+  if (!ctx)
+    return;
+
+  if (ctx->b64state)
+    {
+      b64dec_finish (ctx->b64state);
+      xfree (ctx->b64state);
+    }
+  xfree (ctx);
+}
+
+
+/* Set verbose and debug mode.  */
+void
+mime_parser_set_verbose (mime_parser_t ctx, int level)
+{
+  if (!level)
+    {
+      ctx->verbose = 0;
+      ctx->debug = 0;
+    }
+  else
+    {
+      ctx->verbose = 1;
+      if (level > 10)
+        ctx->debug = 1;
+    }
+}
+
+
+/* Set the callback used to announce a new part.  It will be called
+ * with the media type and media subtype of the part.  If no
+ * Content-type header was given both values are the empty string.
+ * The callback should return 0 on success or an error code.  The
+ * error code GPG_ERR_FALSE indicates that the caller is not
+ * interested in the part and data shall not be returned via a
+ * registered part_data callback.  The error code GPG_ERR_TRUE
+ * indicates that the parts shall be redurned in decoded format
+ * (i.e. base64 or QP encoding is removed).  */
+void
+mime_parser_set_new_part (mime_parser_t ctx,
+                          gpg_error_t (*fnc) (void *cookie,
+                                              const char *mediatype,
+                                              const char *mediasubtype))
+{
+  ctx->new_part = fnc;
+}
+
+
+/* Set the callback used to return the data of a part to the caller.
+ * The end of the part is indicated by passing NUL for DATA.  */
+void
+mime_parser_set_part_data (mime_parser_t ctx,
+                           gpg_error_t (*fnc) (void *cookie,
+                                               const void *data,
+                                               size_t datalen))
+{
+  ctx->part_data = fnc;
+}
+
+
+/* Set the callback to collect encrypted data.  A NULL passed to the
+ * callback indicates the end of the encrypted data; the callback may
+ * then decrypt the collected data.  */
+void
+mime_parser_set_collect_encrypted (mime_parser_t ctx,
+                                   gpg_error_t (*fnc) (void *cookie,
+                                                       const char *data))
+{
+  ctx->collect_encrypted = fnc;
+}
+
+
+/* Set the callback to collect signed data.  A NULL passed to the
+ * callback indicates the end of the signed data.  */
+void
+mime_parser_set_collect_signeddata (mime_parser_t ctx,
+                                    gpg_error_t (*fnc) (void *cookie,
+                                                        const char *data))
+{
+  ctx->collect_signeddata = fnc;
+}
+
+
+/* Set the callback to collect the signature.  A NULL passed to the
+ * callback indicates the end of the signature; the callback may the
+ * verify the signature.  */
+void
+mime_parser_set_collect_signature (mime_parser_t ctx,
+                                   gpg_error_t (*fnc) (void *cookie,
+                                                       const char *data))
+{
+  ctx->collect_signature = fnc;
+}
+
+
+/* Read and parse a message from FP and call the appropriate
+ * callbacks.  */
+gpg_error_t
+mime_parser_parse (mime_parser_t ctx, estream_t fp)
+{
+  gpg_error_t err;
+  rfc822parse_t msg = NULL;
+  unsigned int lineno = 0;
+  size_t length, nbytes;
+  char *line;
+
+  line = ctx->line;
+
+  msg = rfc822parse_open (parse_message_cb, ctx);
+  if (!msg)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("can't open mail parser: %s", gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Fixme: We should not use fgets because it can't cope with
+     embedded nul characters. */
+  while (es_fgets (ctx->line, sizeof (ctx->line), fp))
+    {
+      lineno++;
+      if (lineno == 1 && !strncmp (line, "From ", 5))
+        continue;  /* We better ignore a leading From line. */
+
+      length = strlen (line);
+      if (length && line[length - 1] == '\n')
+       line[--length] = 0;
+      else
+        log_error ("mail parser detected too long or"
+                   " non terminated last line (lnr=%u)\n", lineno);
+      if (length && line[length - 1] == '\r')
+       line[--length] = 0;
+
+      ctx->err = 0;
+      if (rfc822parse_insert (msg, line, length))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("mail parser failed: %s", gpg_strerror (err));
+          goto leave;
+        }
+      if (ctx->err)
+        {
+          /* Error from a callback detected.  */
+          err = ctx->err;
+          goto leave;
+        }
+
+
+      /* Debug output.  Note that the boundary is shown before n_skip
+       * is evaluated.  */
+      if (ctx->show.boundary)
+        {
+          if (ctx->debug)
+            log_debug ("# Boundary: %s\n", line);
+          ctx->show.boundary = 0;
+        }
+      if (ctx->show.n_skip)
+        ctx->show.n_skip--;
+      else if (ctx->show.data)
+        {
+          if (ctx->show.as_note)
+            {
+              if (ctx->verbose)
+                log_debug ("# Note: %s\n", line);
+              ctx->show.as_note = 0;
+            }
+          else if (ctx->debug)
+            log_debug ("# Data: %s\n", line);
+        }
+      else if (ctx->show.header && ctx->verbose)
+        log_debug ("# Header: %s\n", line);
+
+      if (ctx->pgpmime == PGPMIME_IN_ENCVERSION)
+        {
+          trim_trailing_spaces (line);
+          if (!*line)
+            ;  /* Skip empty lines.  */
+          else if (!strcmp (line, "Version: 1"))
+            ctx->pgpmime = PGPMIME_WAIT_ENCDATA;
+          else
+            {
+              log_error ("invalid PGP/MIME structure;"
+                         " garbage in pgp-encrypted part ('%s')\n", line);
+              ctx->pgpmime = PGPMIME_INVALID;
+            }
+        }
+      else if (ctx->pgpmime == PGPMIME_IN_ENCDATA)
+        {
+          if (ctx->collect_encrypted)
+            {
+              err = ctx->collect_encrypted (ctx->cookie, line);
+              if (!err)
+                err = ctx->collect_encrypted (ctx->cookie, "\r\n");
+              if (err)
+                goto leave;
+            }
+        }
+      else if (ctx->pgpmime == PGPMIME_GOT_ENCDATA)
+        {
+          ctx->pgpmime = PGPMIME_NONE;
+          if (ctx->collect_encrypted)
+            ctx->collect_encrypted (ctx->cookie, NULL);
+        }
+      else if (ctx->pgpmime == PGPMIME_IN_SIGNEDDATA)
+        {
+          /* If we are processing signed data, store the signed data.
+           * We need to delay the hashing of the CR/LF because the
+           * last line ending belongs to the next boundary.  This is
+           * the reason why we can't use the PGPMIME state as a
+           * condition.  */
+          if (ctx->debug)
+            log_debug ("# hashing %s'%s'\n",
+                       ctx->delay_hashing? "CR,LF+":"", line);
+          if (ctx->collect_signeddata)
+            {
+              if (ctx->delay_hashing)
+                ctx->collect_signeddata (ctx->cookie, "\r\n");
+              ctx->collect_signeddata (ctx->cookie, line);
+            }
+          ctx->delay_hashing = 1;
+        }
+      else if (ctx->pgpmime == PGPMIME_IN_SIGNATURE)
+        {
+          if (ctx->collect_signeddata)
+            {
+              ctx->collect_signature (ctx->cookie, line);
+              ctx->collect_signature (ctx->cookie, "\r\n");
+            }
+        }
+      else if (ctx->pgpmime == PGPMIME_GOT_SIGNATURE)
+        {
+          ctx->pgpmime = PGPMIME_NONE;
+          if (ctx->collect_signeddata)
+            ctx->collect_signature (ctx->cookie, NULL);
+        }
+      else if (ctx->want_part)
+        {
+          if (ctx->part_data)
+            {
+              if (ctx->decode_part == 1)
+                {
+                  length = qp_decode (line, length, NULL);
+                }
+              else if (ctx->decode_part == 2)
+                {
+                  log_assert (ctx->b64state);
+                  err = b64dec_proc (ctx->b64state, line, length, &nbytes);
+                  if (err)
+                    goto leave;
+                  length = nbytes;
+                }
+              err = ctx->part_data (ctx->cookie, line, length);
+              if (err)
+                goto leave;
+            }
+        }
+    }
+
+  rfc822parse_close (msg);
+  msg = NULL;
+  err = 0;
+
+ leave:
+  rfc822parse_cancel (msg);
+  return err;
+}
diff --git a/tools/mime-parser.h b/tools/mime-parser.h
new file mode 100644 (file)
index 0000000..ab0d792
--- /dev/null
@@ -0,0 +1,52 @@
+/* mime-parser.h - Parse MIME structures (high level rfc822 parser).
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_MIME_PARSER_H
+#define GNUPG_MIME_PARSER_H
+
+struct mime_parser_context_s;
+typedef struct mime_parser_context_s *mime_parser_t;
+
+gpg_error_t mime_parser_new (mime_parser_t *r_ctx, void *cookie);
+void        mime_parser_release (mime_parser_t ctx);
+
+void mime_parser_set_verbose (mime_parser_t ctx, int level);
+void mime_parser_set_new_part (mime_parser_t ctx,
+                               gpg_error_t (*fnc) (void *cookie,
+                                                   const char *mediatype,
+                                                   const char *mediasubtype));
+void mime_parser_set_part_data (mime_parser_t ctx,
+                                gpg_error_t (*fnc) (void *cookie,
+                                                    const void *data,
+                                                    size_t datalen));
+void mime_parser_set_collect_encrypted (mime_parser_t ctx,
+                                        gpg_error_t (*fnc) (void *cookie,
+                                                            const char *data));
+void mime_parser_set_collect_signeddata (mime_parser_t ctx,
+                                         gpg_error_t (*fnc) (void *cookie,
+                                                             const char *data));
+void mime_parser_set_collect_signature (mime_parser_t ctx,
+                                        gpg_error_t (*fnc) (void *cookie,
+                                                            const char *data));
+
+gpg_error_t mime_parser_parse (mime_parser_t ctx, estream_t fp);
+
+
+
+#endif /*GNUPG_MIME_PARSER_H*/
index 8bb5536..c5579fe 100644 (file)
@@ -1,6 +1,6 @@
 /* rfc822parse.h - Simple mail and MIME parser
  *     Copyright (C) 1999 Werner Koch, Duesseldorf
- *      Copyright (C) 2003, g10 Code GmbH
+ *      Copyright (C) 2003 g10 Code GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
diff --git a/tools/send-mail.c b/tools/send-mail.c
new file mode 100644 (file)
index 0000000..2266521
--- /dev/null
@@ -0,0 +1,129 @@
+/* send-mail.c - Invoke sendmail or other delivery tool.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "exectool.h"
+#include "sysutils.h"
+#include "send-mail.h"
+
+
+static gpg_error_t
+run_sendmail (estream_t data)
+{
+  gpg_error_t err;
+  const char pgmname[] = "/usr/lib/sendmail";
+  const char *argv[3];
+
+  argv[0] = "-oi";
+  argv[1] = "-t";
+  argv[2] = NULL;
+
+  err = gnupg_exec_tool_stream (pgmname, argv, data, NULL, NULL, NULL, NULL);
+  if (err)
+    log_error ("running '%s' failed: %s\n", pgmname, gpg_strerror (err));
+  return err;
+}
+
+
+/* Send the data in FP as mail.  */
+gpg_error_t
+send_mail (estream_t fp)
+{
+  return run_sendmail (fp);
+}
+
+
+/* Convenience function to write a mail to a named file. */
+gpg_error_t
+send_mail_to_file (estream_t fp, const char *fname)
+{
+  gpg_error_t err;
+  estream_t outfp = NULL;
+  char *buffer = NULL;
+  size_t buffersize = 32 * 1024;
+  size_t nbytes, nwritten;
+
+  if (!fname)
+    fname = "-";
+
+  buffer = xtrymalloc (buffersize);
+  if (!buffer)
+    return gpg_error_from_syserror ();
+
+  outfp = !strcmp (fname,"-")? es_stdout : es_fopen (fname, "wb");
+  if (!outfp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error creating '%s': %s\n", fname, gpg_strerror (err));
+      goto leave;
+    }
+  for (;;)
+    {
+      if (es_read (fp, buffer, sizeof buffer, &nbytes))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error reading '%s': %s\n",
+                     es_fname_get (fp), gpg_strerror (err));
+          goto leave;
+        }
+
+      if (!nbytes)
+        {
+          err = 0;
+          break; /* Ready.  */
+        }
+
+      if (es_write (outfp, buffer, nbytes, &nwritten))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
+          goto leave;
+        }
+      else if (nwritten != nbytes)
+        {
+          err = gpg_error (GPG_ERR_EIO);
+          log_error ("error writing '%s': %s\n", fname, "short write");
+          goto leave;
+        }
+    }
+
+
+ leave:
+  if (err)
+    {
+      if (outfp && outfp != es_stdout)
+        {
+          es_fclose (outfp);
+          gnupg_remove (fname);
+        }
+    }
+  else if (outfp && outfp != es_stdout && es_fclose (outfp))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
+    }
+
+  xfree (buffer);
+  return err;
+}
diff --git a/tools/send-mail.h b/tools/send-mail.h
new file mode 100644 (file)
index 0000000..5f57854
--- /dev/null
@@ -0,0 +1,27 @@
+/* send-mail.h - Invoke sendmail or other delivery tool.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_SEND_MAIL_H
+#define GNUPG_SEND_MAIL_H
+
+gpg_error_t send_mail (estream_t fp);
+gpg_error_t send_mail_to_file (estream_t fp, const char *fname);
+
+
+#endif /*GNUPG_SEND_MAIL_H*/
diff --git a/tools/wks-receive.c b/tools/wks-receive.c
new file mode 100644 (file)
index 0000000..59141fc
--- /dev/null
@@ -0,0 +1,464 @@
+/* wks-receive.c - Receive a WKS mail
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "ccparray.h"
+#include "exectool.h"
+#include "gpg-wks.h"
+#include "mime-parser.h"
+
+
+/* Limit of acceptable signed data.  */
+#define MAX_SIGNEDDATA 10000
+
+/* Limit of acceptable signature.  */
+#define MAX_SIGNATURE 10000
+
+/* Limit of acceptable encrypted data.  */
+#define MAX_ENCRYPTED 100000
+
+/* Data for a received object.  */
+struct receive_ctx_s
+{
+  estream_t encrypted;
+  estream_t plaintext;
+  estream_t signeddata;
+  estream_t signature;
+  estream_t key_data;
+  estream_t wkd_data;
+  unsigned int collect_key_data:1;
+  unsigned int collect_wkd_data:1;
+};
+typedef struct receive_ctx_s *receive_ctx_t;
+
+
+
+static void
+decrypt_data_status_cb (void *opaque, const char *keyword, char *args)
+{
+  receive_ctx_t ctx = opaque;
+  (void)ctx;
+  log_debug ("%s: %s\n", keyword, args);
+}
+
+
+/* Decrypt the collected data.  */
+static void
+decrypt_data (receive_ctx_t ctx)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+  int c;
+
+  es_rewind (ctx->encrypted);
+
+  if (!ctx->plaintext)
+    ctx->plaintext = es_fopenmem (0, "w+b");
+  if (!ctx->plaintext)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating space for plaintext: %s\n",
+                 gpg_strerror (err));
+      return;
+    }
+
+  ccparray_init (&ccp, 0);
+
+  /* We limit the output to 64 KiB to avoid DoS using compression
+   * tricks.  A regular client will anyway only send a minimal key;
+   * that is one w/o key signatures and attribute packets.  */
+  ccparray_put (&ccp, "--max-output=0xf0000"); /*FIXME: Change s/F/1/ */
+  ccparray_put (&ccp, "--batch");
+  if (opt.verbose)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--always-trust");
+  ccparray_put (&ccp, "--decrypt");
+  ccparray_put (&ccp, "--");
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, ctx->encrypted,
+                                NULL, ctx->plaintext,
+                                decrypt_data_status_cb, ctx);
+  if (err)
+    {
+      log_error ("decryption failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  if (opt.debug)
+    {
+      es_rewind (ctx->plaintext);
+      log_debug ("plaintext: '");
+      while ((c = es_getc (ctx->plaintext)) != EOF)
+        log_printf ("%c", c);
+      log_printf ("'\n");
+    }
+  es_rewind (ctx->plaintext);
+
+ leave:
+  xfree (argv);
+}
+
+
+static void
+verify_signature_status_cb (void *opaque, const char *keyword, char *args)
+{
+  receive_ctx_t ctx = opaque;
+  (void)ctx;
+  log_debug ("%s: %s\n", keyword, args);
+}
+
+/* Verify the signed data.  */
+static void
+verify_signature (receive_ctx_t ctx)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+
+  log_assert (ctx->signeddata);
+  log_assert (ctx->signature);
+  es_rewind (ctx->signeddata);
+  es_rewind (ctx->signature);
+
+  ccparray_init (&ccp, 0);
+
+  ccparray_put (&ccp, "--batch");
+  if (opt.verbose)
+    ccparray_put (&ccp, "--verbose");
+  ccparray_put (&ccp, "--enable-special-filenames");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--verify");
+  ccparray_put (&ccp, "--");
+  ccparray_put (&ccp, "-&@INEXTRA@");
+  ccparray_put (&ccp, "-");
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (opt.gpg_program, argv, ctx->signeddata,
+                                ctx->signature, NULL,
+                                verify_signature_status_cb, ctx);
+  if (err)
+    {
+      log_error ("verification failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+ leave:
+  xfree (argv);
+}
+
+
+static gpg_error_t
+collect_encrypted (void *cookie, const char *data)
+{
+  receive_ctx_t ctx = cookie;
+
+  if (!ctx->encrypted)
+    if (!(ctx->encrypted = es_fopenmem (MAX_ENCRYPTED, "w+b,samethread")))
+      return gpg_error_from_syserror ();
+  if (data)
+    es_fputs (data, ctx->encrypted);
+
+  if (es_ferror (ctx->encrypted))
+    return gpg_error_from_syserror ();
+
+  if (!data)
+    {
+      decrypt_data (ctx);
+    }
+
+  return 0;
+}
+
+
+static gpg_error_t
+collect_signeddata (void *cookie, const char *data)
+{
+  receive_ctx_t ctx = cookie;
+
+  if (!ctx->signeddata)
+    if (!(ctx->signeddata = es_fopenmem (MAX_SIGNEDDATA, "w+b,samethread")))
+      return gpg_error_from_syserror ();
+  if (data)
+    es_fputs (data, ctx->signeddata);
+
+  if (es_ferror (ctx->signeddata))
+    return gpg_error_from_syserror ();
+  return 0;
+}
+
+static gpg_error_t
+collect_signature (void *cookie, const char *data)
+{
+  receive_ctx_t ctx = cookie;
+
+  if (!ctx->signature)
+    if (!(ctx->signature = es_fopenmem (MAX_SIGNATURE, "w+b,samethread")))
+      return gpg_error_from_syserror ();
+  if (data)
+    es_fputs (data, ctx->signature);
+
+  if (es_ferror (ctx->signature))
+    return gpg_error_from_syserror ();
+
+  if (!data)
+    {
+      verify_signature (ctx);
+    }
+
+  return 0;
+}
+
+
+static gpg_error_t
+new_part (void *cookie, const char *mediatype, const char *mediasubtype)
+{
+  receive_ctx_t ctx = cookie;
+  gpg_error_t err = 0;
+
+  ctx->collect_key_data = 0;
+  ctx->collect_wkd_data = 0;
+
+  if (!strcmp (mediatype, "application")
+      && !strcmp (mediasubtype, "pgp-keys"))
+    {
+      log_info ("new '%s/%s' message part\n", mediatype, mediasubtype);
+      if (ctx->key_data)
+        {
+          log_error ("we already got a key - ignoring this part\n");
+          err = gpg_error (GPG_ERR_FALSE);
+        }
+      else
+        {
+          ctx->key_data = es_fopenmem (0, "w+b");
+          if (!ctx->key_data)
+            {
+              err = gpg_error_from_syserror ();
+              log_error ("error allocating space for key: %s\n",
+                         gpg_strerror (err));
+            }
+          else
+            {
+              ctx->collect_key_data = 1;
+              err = gpg_error (GPG_ERR_TRUE); /* We want the part decoded.  */
+            }
+        }
+    }
+  else if (!strcmp (mediatype, "application")
+           && !strcmp (mediasubtype, "vnd.gnupg.wks"))
+    {
+      log_info ("new '%s/%s' message part\n", mediatype, mediasubtype);
+      if (ctx->wkd_data)
+        {
+          log_error ("we already got a wkd part - ignoring this part\n");
+          err = gpg_error (GPG_ERR_FALSE);
+        }
+      else
+        {
+          ctx->wkd_data = es_fopenmem (0, "w+b");
+          if (!ctx->wkd_data)
+            {
+              err = gpg_error_from_syserror ();
+              log_error ("error allocating space for key: %s\n",
+                         gpg_strerror (err));
+            }
+          else
+            {
+              ctx->collect_wkd_data = 1;
+              err = gpg_error (GPG_ERR_TRUE); /* We want the part decoded.  */
+            }
+        }
+    }
+  else
+    {
+      log_error ("unexpected '%s/%s' message part\n", mediatype, mediasubtype);
+      err = gpg_error (GPG_ERR_FALSE); /* We do not want the part.  */
+    }
+
+  return err;
+}
+
+
+static gpg_error_t
+part_data (void *cookie, const void *data, size_t datalen)
+{
+  receive_ctx_t ctx = cookie;
+
+  if (data)
+    {
+      if (opt.debug)
+        log_debug ("part_data: '%.*s'\n", (int)datalen, (const char*)data);
+      if (ctx->collect_key_data)
+        {
+          if (es_write (ctx->key_data, data, datalen, NULL)
+              || es_fputs ("\n", ctx->key_data))
+            return gpg_error_from_syserror ();
+        }
+      if (ctx->collect_wkd_data)
+        {
+          if (es_write (ctx->wkd_data, data, datalen, NULL)
+              || es_fputs ("\n", ctx->wkd_data))
+            return gpg_error_from_syserror ();
+        }
+    }
+  else
+    {
+      if (opt.debug)
+        log_debug ("part_data: finished\n");
+      ctx->collect_key_data = 0;
+      ctx->collect_wkd_data = 0;
+    }
+  return 0;
+}
+
+
+/* Receive a WKS mail from FP and process it accordingly.  On success
+ * the RESULT_CB is called with the mediatype and a stream with the
+ * decrypted data. */
+gpg_error_t
+wks_receive (estream_t fp,
+             gpg_error_t (*result_cb)(void *opaque,
+                                      const char *mediatype,
+                                      estream_t data),
+             void *cb_data)
+{
+  gpg_error_t err;
+  receive_ctx_t ctx;
+  mime_parser_t parser;
+  estream_t plaintext = NULL;
+  int c;
+
+  ctx = xtrycalloc (1, sizeof *ctx);
+  if (!ctx)
+    return gpg_error_from_syserror ();
+
+  err = mime_parser_new (&parser, ctx);
+  if (err)
+    goto leave;
+  if (opt.verbose > 1 || opt.debug)
+    mime_parser_set_verbose (parser, opt.debug? 10: 1);
+  mime_parser_set_new_part (parser, new_part);
+  mime_parser_set_part_data (parser, part_data);
+  mime_parser_set_collect_encrypted (parser, collect_encrypted);
+  mime_parser_set_collect_signeddata (parser, collect_signeddata);
+  mime_parser_set_collect_signature (parser, collect_signature);
+
+  err = mime_parser_parse (parser, fp);
+  if (err)
+    goto leave;
+
+  if (ctx->key_data)
+    log_info ("key data found\n");
+  if (ctx->wkd_data)
+    log_info ("wkd data found\n");
+
+  if (ctx->plaintext)
+    {
+      if (opt.verbose)
+        log_info ("parsing decrypted message\n");
+      plaintext = ctx->plaintext;
+      ctx->plaintext = NULL;
+      if (ctx->encrypted)
+        es_rewind (ctx->encrypted);
+      if (ctx->signeddata)
+        es_rewind (ctx->signeddata);
+      if (ctx->signature)
+        es_rewind (ctx->signature);
+      err = mime_parser_parse (parser, plaintext);
+      if (err)
+        return err;
+    }
+
+  if (!ctx->key_data && !ctx->wkd_data)
+    {
+      log_error ("no suitable data found in the message\n");
+      err = gpg_error (GPG_ERR_NO_DATA);
+      goto leave;
+    }
+
+  if (ctx->key_data)
+    {
+      if (opt.debug)
+        {
+          es_rewind (ctx->key_data);
+          log_debug ("Key: '");
+          log_printf ("\n");
+          while ((c = es_getc (ctx->key_data)) != EOF)
+            log_printf ("%c", c);
+          log_printf ("'\n");
+        }
+      if (result_cb)
+        {
+          es_rewind (ctx->key_data);
+          err = result_cb (cb_data, "application/pgp-keys", ctx->key_data);
+          if (err)
+            goto leave;
+        }
+    }
+  if (ctx->wkd_data)
+    {
+      if (opt.debug)
+        {
+          es_rewind (ctx->wkd_data);
+          log_debug ("WKD: '");
+          log_printf ("\n");
+          while ((c = es_getc (ctx->wkd_data)) != EOF)
+            log_printf ("%c", c);
+          log_printf ("'\n");
+        }
+      if (result_cb)
+        {
+          es_rewind (ctx->wkd_data);
+          err = result_cb (cb_data, "application/vnd.gnupg.wks", ctx->wkd_data);
+          if (err)
+            goto leave;
+        }
+    }
+
+
+ leave:
+  es_fclose (plaintext);
+  mime_parser_release (parser);
+  es_fclose (ctx->encrypted);
+  es_fclose (ctx->plaintext);
+  es_fclose (ctx->signeddata);
+  es_fclose (ctx->signature);
+  es_fclose (ctx->key_data);
+  es_fclose (ctx->wkd_data);
+  xfree (ctx);
+  return err;
+}
diff --git a/tools/wks-util.c b/tools/wks-util.c
new file mode 100644 (file)
index 0000000..8d9f92b
--- /dev/null
@@ -0,0 +1,65 @@
+/* wks-utils.c - Common helper fucntions for wks tools
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "mime-maker.h"
+#include "send-mail.h"
+#include "gpg-wks.h"
+
+
+/* Helper to write mail to the output(s).  */
+gpg_error_t
+wks_send_mime (mime_maker_t mime)
+{
+  gpg_error_t err;
+  estream_t mail;
+
+  /* Without any option we take a short path.  */
+  if (!opt.use_sendmail && !opt.output)
+    return mime_maker_make (mime, es_stdout);
+
+  mail = es_fopenmem (0, "w+b");
+  if (!mail)
+    {
+      err = gpg_error_from_syserror ();
+      return err;
+    }
+
+  err = mime_maker_make (mime, mail);
+
+  if (!err && opt.output)
+    {
+      es_rewind (mail);
+      err = send_mail_to_file (mail, opt.output);
+    }
+
+  if (!err && opt.use_sendmail)
+    {
+      es_rewind (mail);
+      err = send_mail (mail);
+    }
+
+  es_fclose (mail);
+  return err;
+}