g10: Support armored keyrings in gpgv.
[gnupg.git] / g10 / gpg.c
index 5e929d9..bb5e847 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,6 +1,7 @@
 /* gpg.c - The GnuPG utility (main for gpg)
  * Copyright (C) 1998-2011 Free Software Foundation, Inc.
- * Copyright (C) 1997-2014 Werner Koch
+ * Copyright (C) 1997-2016 Werner Koch
+ * Copyright (C) 2015-2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -58,6 +59,7 @@
 #include "gc-opt-flags.h"
 #include "asshelp.h"
 #include "call-dirmngr.h"
+#include "tofu.h"
 #include "../common/init.h"
 #include "../common/shareddefs.h"
 
@@ -115,7 +117,9 @@ enum cmd_and_opt_values
     aLSignKey,
     aQuickSignKey,
     aQuickLSignKey,
+    aQuickAddUid,
     aListConfig,
+    aListGcryptConfig,
     aGPGConfList,
     aGPGConfTest,
     aListPackets,
@@ -137,6 +141,7 @@ enum cmd_and_opt_values
     aExport,
     aExportSecret,
     aExportSecretSub,
+    aExportSshKey,
     aCheckKeys,
     aGenRevoke,
     aDesigRevoke,
@@ -159,6 +164,7 @@ enum cmd_and_opt_values
     aChangePIN,
     aPasswd,
     aServer,
+    aTOFUPolicy,
 
     oTextmode,
     oNoTextmode,
@@ -176,6 +182,7 @@ enum cmd_and_opt_values
     oNoAskCertLevel,
     oFingerprint,
     oWithFingerprint,
+    oWithICAOSpelling,
     oWithKeygrip,
     oWithSecret,
     oAnswerYes,
@@ -193,7 +200,7 @@ enum cmd_and_opt_values
     oDebug,
     oDebugLevel,
     oDebugAll,
-    oDebugCCIDDriver,
+    oDebugIOLBF,
     oStatusFD,
     oStatusFile,
     oAttributeFD,
@@ -297,6 +304,7 @@ enum cmd_and_opt_values
     oEncryptTo,
     oHiddenEncryptTo,
     oNoEncryptTo,
+    oEncryptToDefaultKey,
     oLoggerFD,
     oLoggerFile,
     oUtf8Strings,
@@ -333,7 +341,6 @@ enum cmd_and_opt_values
     oFixedListMode,
     oLegacyListMode,
     oNoSigCache,
-    oNoSigCreateCheck,
     oAutoCheckTrustDB,
     oNoAutoCheckTrustDB,
     oPreservePermissions,
@@ -380,6 +387,13 @@ enum cmd_and_opt_values
     oAllowWeakDigestAlgos,
     oFakedSystemTime,
     oNoAutostart,
+    oPrintPKARecords,
+    oPrintDANERecords,
+    oTOFUDefaultPolicy,
+    oTOFUDBFormat,
+    oWeakDigest,
+    oUnwrap,
+    oOnlySignTextIDs,
 
     oNoop
   };
@@ -410,6 +424,8 @@ static ARGPARSE_OPTS opts[] = {
               N_("generate a new key pair")),
   ARGPARSE_c (aQuickKeygen, "quick-gen-key" ,
               N_("quickly generate a new key pair")),
+  ARGPARSE_c (aQuickAddUid,  "quick-adduid",
+              N_("quickly add a new user-id")),
   ARGPARSE_c (aFullKeygen,  "full-gen-key" ,
               N_("full featured key pair generation")),
   ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
@@ -438,6 +454,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
   ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
   ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ),
+  ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ),
   ARGPARSE_c (aImport, "import", N_("import/merge keys")),
   ARGPARSE_c (aFastImport, "fast-import", "@"),
 #ifdef ENABLE_CARD_SUPPORT
@@ -446,6 +463,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aChangePIN,  "change-pin", N_("change a card's PIN")),
 #endif
   ARGPARSE_c (aListConfig, "list-config", "@"),
+  ARGPARSE_c (aListGcryptConfig, "list-gcrypt-config", "@"),
   ARGPARSE_c (aGPGConfList, "gpgconf-list", "@" ),
   ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@" ),
   ARGPARSE_c (aListPackets, "list-packets","@"),
@@ -467,6 +485,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aPrimegen, "gen-prime", "@" ),
   ARGPARSE_c (aGenRandom,"gen-random", "@" ),
   ARGPARSE_c (aServer,   "server",  N_("run in server mode")),
+  ARGPARSE_c (aTOFUPolicy, "tofu-policy",
+             N_("|VALUE|set the TOFU policy for a key")),
 
   ARGPARSE_group (301, N_("@\nOptions:\n ")),
 
@@ -485,6 +505,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oEncryptTo,      "encrypt-to", "@"),
   ARGPARSE_s_n (oNoEncryptTo, "no-encrypt-to", "@"),
   ARGPARSE_s_s (oHiddenEncryptTo, "hidden-encrypt-to", "@"),
+  ARGPARSE_s_n (oEncryptToDefaultKey, "encrypt-to-default-key", "@"),
   ARGPARSE_s_s (oLocalUser, "local-user",
                 N_("|USER-ID|use USER-ID to sign or decrypt")),
 
@@ -549,9 +570,10 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oDisplayCharset, "charset", "@"),
   ARGPARSE_s_s (oOptions, "options", "@"),
 
-  ARGPARSE_p_u (oDebug, "debug", "@"),
+  ARGPARSE_s_s (oDebug, "debug", "@"),
   ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
+  ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"),
   ARGPARSE_s_i (oStatusFD, "status-fd", "@"),
   ARGPARSE_s_s (oStatusFile, "status-file", "@"),
   ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"),
@@ -659,8 +681,12 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
   ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
   ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */
+#ifndef NO_TRUST_MODELS
   ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
+#endif
   ARGPARSE_s_s (oTrustModel, "trust-model", "@"),
+  ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"),
+  ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
   ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"),
   ARGPARSE_s_n (oNoForYourEyesOnly, "no-for-your-eyes-only", "@"),
@@ -692,6 +718,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oUtf8Strings,      "utf8-strings", "@"),
   ARGPARSE_s_n (oNoUtf8Strings, "no-utf8-strings", "@"),
   ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
+  ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
   ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
   ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
   ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
@@ -706,6 +733,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oFixedListMode, "fixed-list-mode", "@"),
   ARGPARSE_s_n (oLegacyListMode, "legacy-list-mode", "@"),
   ARGPARSE_s_n (oListOnly, "list-only", "@"),
+  ARGPARSE_s_n (oPrintPKARecords, "print-pka-records", "@"),
+  ARGPARSE_s_n (oPrintDANERecords, "print-dane-records", "@"),
   ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
   ARGPARSE_s_n (oIgnoreValidFrom,    "ignore-valid-from", "@"),
   ARGPARSE_s_n (oIgnoreCrcError, "ignore-crc-error", "@"),
@@ -716,7 +745,6 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oAutoKeyRetrieve, "auto-key-retrieve", "@"),
   ARGPARSE_s_n (oNoAutoKeyRetrieve, "no-auto-key-retrieve", "@"),
   ARGPARSE_s_n (oNoSigCache,         "no-sig-cache", "@"),
-  ARGPARSE_s_n (oNoSigCreateCheck,   "no-sig-create-check", "@"),
   ARGPARSE_s_n (oMergeOnly,      "merge-only", "@" ),
   ARGPARSE_s_n (oAllowSecretKeyImport, "allow-secret-key-import", "@"),
   ARGPARSE_s_n (oTryAllSecrets,  "try-all-secrets", "@"),
@@ -730,6 +758,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oPersonalCompressPreferences,
                                          "personal-compress-preferences", "@"),
   ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
+  ARGPARSE_s_s (oWeakDigest, "weak-digest","@"),
+  ARGPARSE_s_n (oUnwrap, "unwrap", "@"),
+  ARGPARSE_s_n (oOnlySignTextIDs, "only-sign-text-ids", "@"),
 
   /* Aliases.  I constantly mistype these, and assume other people do
      as well. */
@@ -809,6 +840,28 @@ static ARGPARSE_OPTS opts[] = {
 };
 
 
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_PACKET_VALUE , "packet"  },
+    { DBG_MPI_VALUE    , "mpi"     },
+    { DBG_CRYPTO_VALUE , "crypto"  },
+    { DBG_FILTER_VALUE , "filter"  },
+    { DBG_IOBUF_VALUE  , "iobuf"   },
+    { DBG_MEMORY_VALUE , "memory"  },
+    { DBG_CACHE_VALUE  , "cache"   },
+    { DBG_MEMSTAT_VALUE, "memstat" },
+    { DBG_TRUST_VALUE  , "trust"   },
+    { DBG_HASHING_VALUE, "hashing" },
+    { DBG_CARD_IO_VALUE, "cardio"  },
+    { DBG_IPC_VALUE    , "ipc"     },
+    { DBG_CLOCK_VALUE  , "clock"   },
+    { DBG_LOOKUP_VALUE , "lookup"  },
+    { DBG_EXTPROG_VALUE, "extprog" },
+    { 0, NULL }
+  };
+
+
 #ifdef ENABLE_SELINUX_HACKS
 #define ALWAYS_ADD_KEYRINGS 1
 #else
@@ -994,7 +1047,7 @@ build_list (const char *text, char letter,
   if (maybe_setuid)
     gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
 
-  indent = utf8_charcount (text);
+  indent = utf8_charcount (text, -1);
   len = 0;
   init_membuf (&mb, 512);
 
@@ -1038,7 +1091,7 @@ build_list (const char *text, char letter,
 static void
 wrong_args( const char *text)
 {
-  fprintf (stderr, _("usage: %s [options] %s\n"), GPG_NAME, text);
+  es_fprintf (es_stderr, _("usage: %s [options] %s\n"), GPG_NAME, text);
   g10_exit(2);
 }
 
@@ -1066,6 +1119,7 @@ set_opt_session_env (const char *name, const char *value)
                gpg_strerror (err));
 }
 
+
 /* Setup the debugging.  With a LEVEL of NULL only the active debug
    flags are propagated to the subsystems.  With LEVEL set, a specific
    set of debug flags is set; thus overriding all flags already
@@ -1086,7 +1140,7 @@ set_debug (const char *level)
     opt.debug = DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE;
   else if (!strcmp (level, "expert")  || (numok && numlvl <= 8))
     opt.debug = (DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE
-                 |DBG_CACHE_VALUE|DBG_FILTER_VALUE|DBG_PACKET_VALUE);
+                 |DBG_CACHE_VALUE|DBG_LOOKUP|DBG_FILTER_VALUE|DBG_PACKET_VALUE);
   else if (!strcmp (level, "guru") || numok)
     {
       opt.debug = ~0;
@@ -1109,28 +1163,14 @@ set_debug (const char *level)
     memory_stat_debug_mode = 1;
   if (opt.debug & DBG_MPI_VALUE)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
-  if (opt.debug & DBG_CIPHER_VALUE )
+  if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
   if (opt.debug & DBG_IOBUF_VALUE )
     iobuf_debug_mode = 1;
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 
   if (opt.debug)
-    log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
-              (opt.debug & DBG_PACKET_VALUE )? " packet":"",
-              (opt.debug & DBG_MPI_VALUE    )? " mpi":"",
-              (opt.debug & DBG_CIPHER_VALUE )? " cipher":"",
-              (opt.debug & DBG_FILTER_VALUE )? " filter":"",
-              (opt.debug & DBG_IOBUF_VALUE  )? " iobuf":"",
-              (opt.debug & DBG_MEMORY_VALUE )? " memory":"",
-              (opt.debug & DBG_CACHE_VALUE  )? " cache":"",
-              (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
-              (opt.debug & DBG_TRUST_VALUE  )? " trust":"",
-              (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
-              (opt.debug & DBG_EXTPROG_VALUE)? " extprog":"",
-              (opt.debug & DBG_CARD_IO_VALUE)? " cardio":"",
-              (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"",
-              (opt.debug & DBG_CLOCK_VALUE  )? " clock":"");
+    parse_debug_flag (NULL, &opt.debug, debug_flags);
 }
 
 
@@ -1574,8 +1614,11 @@ print_algo_names(int (*checker)(int),const char *(*mapper)(int))
 static void
 list_config(char *items)
 {
-  int show_all=(items==NULL);
-  char *name=NULL;
+  int show_all = !items;
+  char *name = NULL;
+  const char *s;
+  struct groupitem *giter;
+  int first, iter;
 
   if(!opt.with_colons)
     return;
@@ -1586,20 +1629,19 @@ list_config(char *items)
 
       if(show_all || ascii_strcasecmp(name,"group")==0)
        {
-         struct groupitem *iter;
-
-         for(iter=opt.grouplist;iter;iter=iter->next)
+         for (giter = opt.grouplist; giter; giter = giter->next)
            {
              strlist_t sl;
 
              es_fprintf (es_stdout, "cfg:group:");
-             es_write_sanitized (es_stdout, iter->name, strlen(iter->name),
+             es_write_sanitized (es_stdout, giter->name, strlen(giter->name),
                                   ":", NULL);
              es_putc (':', es_stdout);
 
-             for(sl=iter->values;sl;sl=sl->next)
+             for(sl=giter->values; sl; sl=sl->next)
                {
-                 print_sanitized_string2 (stdout, sl->d, ':',';');
+                 es_write_sanitized (es_stdout, sl->d, strlen (sl->d),
+                                      ":;", NULL);
                  if(sl->next)
                     es_printf(";");
                }
@@ -1681,20 +1723,31 @@ list_config(char *items)
          any=1;
        }
 
-      if(show_all || ascii_strcasecmp(name,"ccid-reader-id")==0)
+      if (show_all || !ascii_strcasecmp(name,"ccid-reader-id"))
        {
-#if defined(ENABLE_CARD_SUPPORT) && defined(HAVE_LIBUSB) \
-    && GNUPG_MAJOR_VERSION == 1
+          /* We ignore this for GnuPG 1.4 backward compatibility.  */
+         any=1;
+       }
 
-          char *p, *p2, *list = ccid_get_reader_list ();
+      if (show_all || !ascii_strcasecmp (name,"curve"))
+       {
+         es_printf ("cfg:curve:");
+          for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first=0)
+            es_printf ("%s%s", first?"":";", s);
+         es_printf ("\n");
+         any=1;
+       }
 
-          for (p=list; p && (p2 = strchr (p, '\n')); p = p2+1)
+      /* Curve OIDs are rarely useful and thus only printed if requested.  */
+      if (name && !ascii_strcasecmp (name,"curveoid"))
+       {
+         es_printf ("cfg:curveoid:");
+          for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first = 0)
             {
-              *p2 = 0;
-              es_printf ("cfg:ccid-reader-id:%s\n", p);
+              s = openpgp_curve_to_oid (s, NULL);
+              es_printf ("%s%s", first?"":";", s? s:"[?]");
             }
-          free (list);
-#endif
+         es_printf ("\n");
          any=1;
        }
 
@@ -1843,7 +1896,7 @@ parse_list_options(char *str)
      compile everywhere, so fill in the show-sig-subpackets argument
      here.  Note that if the parse_options array changes, we'll have
      to change the subscript here. */
-  lopts[12].value=&subpackets;
+  lopts[13].value=&subpackets;
 
   if(parse_options(str,&opt.list_options,lopts,1))
     {
@@ -1906,6 +1959,12 @@ parse_trust_model(const char *model)
     opt.trust_model=TM_ALWAYS;
   else if(ascii_strcasecmp(model,"direct")==0)
     opt.trust_model=TM_DIRECT;
+#ifdef USE_TOFU
+  else if(ascii_strcasecmp(model,"tofu")==0)
+    opt.trust_model=TM_TOFU;
+  else if(ascii_strcasecmp(model,"tofu+pgp")==0)
+    opt.trust_model=TM_TOFU_PGP;
+#endif /*USE_TOFU*/
   else if(ascii_strcasecmp(model,"auto")==0)
     opt.trust_model=TM_AUTO;
   else
@@ -1914,7 +1973,64 @@ parse_trust_model(const char *model)
 #endif /*NO_TRUST_MODELS*/
 
 
-/* This fucntion called to initialized a new control object.  It is
+static int
+parse_tofu_policy (const char *policystr)
+{
+#ifdef USE_TOFU
+  struct { const char *keyword; int policy; } list[] = {
+    { "auto",    TOFU_POLICY_AUTO },
+    { "good",    TOFU_POLICY_GOOD },
+    { "unknown", TOFU_POLICY_UNKNOWN },
+    { "bad",     TOFU_POLICY_BAD },
+    { "ask",     TOFU_POLICY_ASK }
+  };
+  int i;
+
+  if (!ascii_strcasecmp (policystr, "help"))
+    {
+      log_info (_("available TOFU policies:\n"));
+      for (i=0; i < DIM (list); i++)
+        log_info ("  %s\n", list[i].keyword);
+      g10_exit (1);
+    }
+
+  for (i=0; i < DIM (list); i++)
+    if (!ascii_strcasecmp (policystr, list[i].keyword))
+      return list[i].policy;
+#endif /*USE_TOFU*/
+
+  log_error (_("unknown TOFU policy '%s'\n"), policystr);
+  if (!opt.quiet)
+    log_info (_("(use \"help\" to list choices)\n"));
+  g10_exit (1);
+}
+
+static int
+parse_tofu_db_format (const char *db_format)
+{
+#ifdef USE_TOFU
+  if (ascii_strcasecmp (db_format, "auto") == 0)
+    return TOFU_DB_AUTO;
+  else if (ascii_strcasecmp (db_format, "split") == 0)
+    return TOFU_DB_SPLIT;
+  else if (ascii_strcasecmp (db_format, "flat") == 0)
+    return TOFU_DB_FLAT;
+  else if (ascii_strcasecmp (db_format, "help") == 0)
+    {
+      log_info ("available TOFU DB fomats: auto, split, flat\n");
+      g10_exit (1);
+    }
+  else
+#endif /*USE_TOFU*/
+    {
+      log_error (_("unknown TOFU DB format '%s'\n"), db_format);
+      if (!opt.quiet)
+        log_info (_("(use \"help\" to list choices)\n"));
+      g10_exit (1);
+    }
+}
+
+/* This function called to initialized a new control object.  It is
    assumed that this object has been zeroed out before calling this
    function. */
 static void
@@ -1989,7 +2105,6 @@ get_default_configname (void)
   return configname;
 }
 
-
 int
 main (int argc, char **argv)
 {
@@ -2001,7 +2116,9 @@ main (int argc, char **argv)
     const char *fname;
     char *username;
     int may_coredump;
-    strlist_t sl, remusr= NULL, locusr=NULL;
+    strlist_t sl;
+    strlist_t remusr = NULL;
+    strlist_t locusr = NULL;
     strlist_t nrings = NULL;
     armor_filter_context_t *afx = NULL;
     int detached_sig = 0;
@@ -2106,18 +2223,20 @@ main (int argc, char **argv)
     opt.export_options = EXPORT_ATTRIBUTES;
     opt.keyserver_options.import_options = IMPORT_REPAIR_PKS_SUBKEY_BUG;
     opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
-    opt.keyserver_options.options = (KEYSERVER_HONOR_KEYSERVER_URL
-                                     | KEYSERVER_HONOR_PKA_RECORD );
+    opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD;
     opt.verify_options = (LIST_SHOW_UID_VALIDITY
                           | VERIFY_SHOW_POLICY_URLS
                           | VERIFY_SHOW_STD_NOTATIONS
                           | VERIFY_SHOW_KEYSERVER_URLS);
-    opt.list_options   = LIST_SHOW_UID_VALIDITY;
+    opt.list_options   = (LIST_SHOW_UID_VALIDITY
+                          | LIST_SHOW_USAGE);
 #ifdef NO_TRUST_MODELS
     opt.trust_model = TM_ALWAYS;
 #else
     opt.trust_model = TM_AUTO;
 #endif
+    opt.tofu_default_policy = TOFU_POLICY_AUTO;
+    opt.tofu_db_format = TOFU_DB_AUTO;
     opt.mangle_dos_filenames = 0;
     opt.min_cert_level = 2;
     set_screen_dimensions ();
@@ -2127,6 +2246,8 @@ main (int argc, char **argv)
     set_homedir (default_homedir ());
     opt.passphrase_repeat = 1;
     opt.emit_version = 1; /* Limit to the major number.  */
+    opt.weak_digests = NULL;
+    additional_weak_digest("MD5");
 
     /* Check whether we have a config file on the command line.  */
     orig_argc = argc;
@@ -2137,6 +2258,8 @@ main (int argc, char **argv)
     while( arg_parse( &pargs, opts) ) {
        if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll )
            parse_debug++;
+       else if (pargs.r_opt == oDebugIOLBF)
+            es_setvbuf (es_stdout, NULL, _IOLBF, 0);
        else if( pargs.r_opt == oOptions ) {
            /* yes there is one, so we do not try the default one, but
             * read the option file when it is encountered at the commandline
@@ -2260,6 +2383,7 @@ main (int argc, char **argv)
          {
          case aCheckKeys:
          case aListConfig:
+         case aListGcryptConfig:
           case aGPGConfList:
           case aGPGConfTest:
          case aListPackets:
@@ -2281,6 +2405,7 @@ main (int argc, char **argv)
          case aListSigs:
          case aExportSecret:
          case aExportSecretSub:
+         case aExportSshKey:
          case aSym:
          case aClearsign:
          case aGenRevoke:
@@ -2303,6 +2428,7 @@ main (int argc, char **argv)
          case aLSignKey:
          case aStore:
          case aQuickKeygen:
+         case aQuickAddUid:
          case aExportOwnerTrust:
          case aImportOwnerTrust:
           case aRebuildKeydbCaches:
@@ -2336,6 +2462,10 @@ main (int argc, char **argv)
             opt.batch = 1;
             break;
 
+          case aTOFUPolicy:
+            set_cmd (&cmd, pargs.r_opt);
+            break;
+
          case oArmor: opt.armor = 1; opt.no_armor=0; break;
          case oOutput: opt.outfile = pargs.r.ret_str; break;
          case oMaxOutput: opt.max_output = pargs.r.ret_ulong; break;
@@ -2393,10 +2523,19 @@ main (int argc, char **argv)
            opt.list_options|=LIST_SHOW_KEYRING;
            break;
 
-         case oDebug: opt.debug |= pargs.r.ret_ulong; 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 oDebugAll: opt.debug = ~0; break;
           case oDebugLevel: debug_level = pargs.r.ret_str; break;
 
+          case oDebugIOLBF: break; /* Already set in pre-parse step.  */
+
          case oStatusFD:
             set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) );
             break;
@@ -2420,6 +2559,9 @@ main (int argc, char **argv)
             opt.with_fingerprint = 1;
             opt.fingerprint++;
             break;
+         case oWithICAOSpelling:
+            opt.with_icao_spelling = 1;
+            break;
          case oFingerprint:
             opt.fingerprint++;
             fpr_maybe_cmd = 1;
@@ -2466,10 +2608,18 @@ main (int argc, char **argv)
          case oTrustDBName: trustdb_name = pargs.r.ret_str; break;
 
 #endif /*!NO_TRUST_MODELS*/
-         case oDefaultKey: opt.def_secret_key = pargs.r.ret_str; break;
+         case oDefaultKey:
+            sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
+            sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
+            break;
          case oDefRecipient:
             if( *pargs.r.ret_str )
-              opt.def_recipient = make_username(pargs.r.ret_str);
+             {
+               xfree (opt.def_recipient);
+               opt.def_recipient = make_username(pargs.r.ret_str);
+             }
             break;
          case oDefRecipientSelf:
             xfree(opt.def_recipient); opt.def_recipient = NULL;
@@ -2505,6 +2655,12 @@ main (int argc, char **argv)
            parse_trust_model(pargs.r.ret_str);
            break;
 #endif /*!NO_TRUST_MODELS*/
+         case oTOFUDefaultPolicy:
+           opt.tofu_default_policy = parse_tofu_policy (pargs.r.ret_str);
+           break;
+         case oTOFUDBFormat:
+           opt.tofu_db_format = parse_tofu_db_format (pargs.r.ret_str);
+           break;
 
          case oForceOwnertrust:
            log_info(_("Note: %s is not for normal use!\n"),
@@ -2648,19 +2804,32 @@ main (int argc, char **argv)
          case oNoEncryptTo: opt.no_encrypt_to = 1; break;
          case oEncryptTo: /* store the recipient in the second list */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = 1;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
          case oHiddenEncryptTo: /* store the recipient in the second list */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = 1|2;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT)
+                         | PK_LIST_ENCRYPT_TO|PK_LIST_HIDDEN);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
+          case oEncryptToDefaultKey:
+            opt.encrypt_to_default_key = configfp ? 2 : 1;
+            break;
          case oRecipient: /* store the recipient */
-           add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
+           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 = 2;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
             any_explicit_recipient = 1;
            break;
 
@@ -2703,7 +2872,10 @@ main (int argc, char **argv)
          case oAskCertLevel: opt.ask_cert_level = 1; break;
          case oNoAskCertLevel: opt.ask_cert_level = 0; break;
          case oLocalUser: /* store the local users */
-           add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
+           sl = add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
+            sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
          case oCompress:
            /* this is the -z command line option */
@@ -2806,7 +2978,13 @@ main (int argc, char **argv)
                log_error (_("could not parse keyserver URL\n"));
              else
                {
-                 keyserver->next = opt.keyserver;
+                 /* We only support a single keyserver.  Later ones
+                    override earlier ones.  (Since we parse the
+                    config file first and then the command line
+                    arguments, the command line takes
+                    precedence.)  */
+                 if (opt.keyserver)
+                   free_keyserver_spec (opt.keyserver);
                  opt.keyserver = keyserver;
                }
            }
@@ -2936,7 +3114,6 @@ main (int argc, char **argv)
             }
             break;
           case oNoSigCache: opt.no_sig_cache = 1; break;
-          case oNoSigCreateCheck: opt.no_sig_create_check = 1; break;
          case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break;
          case oNoAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid=0; break;
          case oAllowFreeformUID: opt.allow_freeform_uid = 1; break;
@@ -2946,6 +3123,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 oListOnly: opt.list_only=1; break;
          case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
          case oIgnoreValidFrom: opt.ignore_valid_from = 1; break;
@@ -3010,6 +3189,15 @@ main (int argc, char **argv)
            break;
           case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
           case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
+          case oWeakDigest:
+           additional_weak_digest(pargs.r.ret_str);
+           break;
+          case oUnwrap:
+            opt.unwrap_encryption = 1;
+            break;
+          case oOnlySignTextIDs:
+            opt.only_sign_text_ids = 1;
+            break;
 
           case oDisplay:
             set_opt_session_env ("DISPLAY", pargs.r.ret_str);
@@ -3264,7 +3452,7 @@ main (int argc, char **argv)
     /* Do these after the switch(), so they can override settings. */
     if(PGP6)
       {
-        /* That does not anymore work becuase we have no more support
+        /* That does not anymore work because we have no more support
            for v3 signatures.  */
        opt.disable_mdc=1;
        opt.escape_from=1;
@@ -3366,6 +3554,9 @@ main (int argc, char **argv)
          case aSign:
            cmdname="--sign";
            break;
+         case aSignEncr:
+           cmdname="--sign --encrypt";
+           break;
          case aClearsign:
            cmdname="--clearsign";
            break;
@@ -3491,6 +3682,13 @@ main (int argc, char **argv)
       }
     FREE_STRLIST(nrings);
 
+    if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
+      /* In loopback mode, never ask for the password multiple
+        times.  */
+      {
+       opt.passphrase_repeat = 0;
+      }
+
     if (cmd == aGPGConfTest)
       g10_exit(0);
 
@@ -3568,6 +3766,7 @@ main (int argc, char **argv)
       case aDeleteSecretKeys:
       case aDeleteSecretAndPublicKeys:
       case aQuickKeygen:
+      case aQuickAddUid:
       case aFullKeygen:
       case aKeygen:
       case aImport:
@@ -3598,15 +3797,21 @@ main (int argc, char **argv)
        if( argc > 1 )
            wrong_args(_("--store [filename]"));
        if( (rc = encrypt_store(fname)) )
+          {
+            write_status_failure ("store", rc);
            log_error ("storing '%s' failed: %s\n",
                        print_fname_stdin(fname),gpg_strerror (rc) );
+          }
        break;
       case aSym: /* encrypt the given file only with the symmetric cipher */
        if( argc > 1 )
            wrong_args(_("--symmetric [filename]"));
        if( (rc = encrypt_symmetric(fname)) )
+          {
+            write_status_failure ("symencrypt", rc);
             log_error (_("symmetric encryption of '%s' failed: %s\n"),
                         print_fname_stdin(fname),gpg_strerror (rc) );
+          }
        break;
 
       case aEncr: /* encrypt the given file */
@@ -3617,8 +3822,11 @@ main (int argc, char **argv)
            if( argc > 1 )
              wrong_args(_("--encrypt [filename]"));
            if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) )
-             log_error("%s: encryption failed: %s\n",
-                       print_fname_stdin(fname), gpg_strerror (rc) );
+              {
+                write_status_failure ("encrypt", rc);
+                log_error("%s: encryption failed: %s\n",
+                          print_fname_stdin(fname), gpg_strerror (rc) );
+              }
          }
        break;
 
@@ -3638,8 +3846,11 @@ main (int argc, char **argv)
        else
          {
            if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) )
-             log_error("%s: encryption failed: %s\n",
-                       print_fname_stdin(fname), gpg_strerror (rc) );
+              {
+                write_status_failure ("encrypt", rc);
+                log_error ("%s: encryption failed: %s\n",
+                           print_fname_stdin(fname), gpg_strerror (rc) );
+              }
          }
        break;
 
@@ -3657,8 +3868,11 @@ main (int argc, char **argv)
                strcpy(sl->d, fname);
            }
        }
-       if( (rc = sign_file (ctrl, sl, detached_sig, locusr, 0, NULL, NULL)) )
-           log_error("signing failed: %s\n", gpg_strerror (rc) );
+       if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 0, NULL, NULL)))
+          {
+            write_status_failure ("sign", rc);
+           log_error ("signing failed: %s\n", gpg_strerror (rc) );
+          }
        free_strlist(sl);
        break;
 
@@ -3672,8 +3886,11 @@ main (int argc, char **argv)
        else
            sl = NULL;
        if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 1, remusr, NULL)))
+          {
+            write_status_failure ("sign-encrypt", rc);
            log_error("%s: sign+encrypt failed: %s\n",
                      print_fname_stdin(fname), gpg_strerror (rc) );
+          }
        free_strlist(sl);
        break;
 
@@ -3697,8 +3914,11 @@ main (int argc, char **argv)
              sl = NULL;
            if ((rc = sign_file (ctrl, sl, detached_sig, locusr,
                                  2, remusr, NULL)))
-             log_error("%s: symmetric+sign+encrypt failed: %s\n",
-                       print_fname_stdin(fname), gpg_strerror (rc) );
+              {
+                write_status_failure ("sign-encrypt", rc);
+                log_error("%s: symmetric+sign+encrypt failed: %s\n",
+                          print_fname_stdin(fname), gpg_strerror (rc) );
+              }
            free_strlist(sl);
          }
        break;
@@ -3706,18 +3926,24 @@ main (int argc, char **argv)
       case aSignSym: /* sign and conventionally encrypt the given file */
        if (argc > 1)
            wrong_args(_("--sign --symmetric [filename]"));
-       rc = sign_symencrypt_file (fname, locusr);
+       rc = sign_symencrypt_file (ctrl, fname, locusr);
         if (rc)
+          {
+            write_status_failure ("sign-symencrypt", rc);
            log_error("%s: sign+symmetric failed: %s\n",
                       print_fname_stdin(fname), gpg_strerror (rc) );
+          }
        break;
 
       case aClearsign: /* make a clearsig */
        if( argc > 1 )
            wrong_args(_("--clearsign [filename]"));
-       if( (rc = clearsign_file(fname, locusr, NULL)) )
+       if( (rc = clearsign_file (ctrl, fname, locusr, NULL)) )
+          {
+            write_status_failure ("sign", rc);
            log_error("%s: clearsign failed: %s\n",
                       print_fname_stdin(fname), gpg_strerror (rc) );
+          }
        break;
 
       case aVerify:
@@ -3731,6 +3957,8 @@ main (int argc, char **argv)
            if ((rc = verify_signatures (ctrl, argc, argv)))
              log_error("verify signatures failed: %s\n", gpg_strerror (rc) );
          }
+        if (rc)
+          write_status_failure ("verify", rc);
        break;
 
       case aDecrypt:
@@ -3741,7 +3969,10 @@ main (int argc, char **argv)
            if( argc > 1 )
              wrong_args(_("--decrypt [filename]"));
            if( (rc = decrypt_message (ctrl, fname) ))
-             log_error("decrypt_message failed: %s\n", gpg_strerror (rc) );
+              {
+                write_status_failure ("decrypt", rc);
+                log_error("decrypt_message failed: %s\n", gpg_strerror (rc) );
+              }
          }
        break;
 
@@ -3856,7 +4087,7 @@ main (int argc, char **argv)
         if (argc != 1 )
           wrong_args("--gen-key user-id");
         username = make_username (fname);
-        quick_generate_keypair (username);
+        quick_generate_keypair (ctrl, username);
         xfree (username);
         break;
 
@@ -3867,9 +4098,18 @@ main (int argc, char **argv)
            generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0);
        }
        else {
-           if( argc )
-               wrong_args("--gen-key");
-           generate_keypair (ctrl, 0, NULL, NULL, 0);
+            if (opt.command_fd != -1 && argc)
+              {
+                if( argc > 1 )
+                  wrong_args("--gen-key [parameterfile]");
+
+                opt.batch = 1;
+                generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0);
+              }
+            else if (argc)
+              wrong_args ("--gen-key");
+            else
+              generate_keypair (ctrl, 0, NULL, NULL, 0);
        }
        break;
 
@@ -3888,6 +4128,18 @@ main (int argc, char **argv)
        }
        break;
 
+      case aQuickAddUid:
+        {
+          const char *uid, *newuid;
+
+          if (argc != 2)
+            wrong_args ("--quick-adduid USER-ID NEW-USER-ID");
+          uid = *argv++; argc--;
+          newuid = *argv++; argc--;
+          keyedit_quick_adduid (ctrl, uid, newuid);
+        }
+       break;
+
       case aFastImport:
         opt.import_options |= IMPORT_FAST;
       case aImport:
@@ -3910,26 +4162,55 @@ main (int argc, char **argv)
        else if( cmd == aRecvKeys )
             rc = keyserver_import (ctrl, sl );
        else
-            rc = export_pubkeys (ctrl, sl, opt.export_options);
+          {
+            export_stats_t stats = export_new_stats ();
+            rc = export_pubkeys (ctrl, sl, opt.export_options, stats);
+            export_print_stats (stats);
+            export_release_stats (stats);
+          }
        if(rc)
          {
            if(cmd==aSendKeys)
-             log_error(_("keyserver send failed: %s\n"),gpg_strerror (rc));
+              {
+                write_status_failure ("send-keys", rc);
+                log_error(_("keyserver send failed: %s\n"),gpg_strerror (rc));
+              }
            else if(cmd==aRecvKeys)
-             log_error(_("keyserver receive failed: %s\n"),gpg_strerror (rc));
+              {
+                write_status_failure ("recv-keys", rc);
+                log_error (_("keyserver receive failed: %s\n"),
+                           gpg_strerror (rc));
+              }
            else
-             log_error(_("key export failed: %s\n"),gpg_strerror (rc));
+              {
+                write_status_failure ("export", rc);
+                log_error (_("key export failed: %s\n"), gpg_strerror (rc));
+              }
          }
        free_strlist(sl);
        break;
 
+      case aExportSshKey:
+        if (argc != 1)
+          wrong_args ("--export-ssh-key <user-id>");
+        rc = export_ssh_key (ctrl, argv[0]);
+        if (rc)
+          {
+            write_status_failure ("export-ssh-key", rc);
+            log_error (_("export as ssh key failed: %s\n"), gpg_strerror (rc));
+          }
+       break;
+
      case aSearchKeys:
        sl = NULL;
        for (; argc; argc--, argv++)
          append_to_strlist2 (&sl, *argv, utf8_strings);
        rc = keyserver_search (ctrl, sl);
        if (rc)
-         log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc));
+          {
+            write_status_failure ("search-keys", rc);
+            log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc));
+          }
        free_strlist (sl);
        break;
 
@@ -3939,7 +4220,10 @@ main (int argc, char **argv)
            append_to_strlist2( &sl, *argv, utf8_strings );
        rc = keyserver_refresh (ctrl, sl);
        if(rc)
-         log_error(_("keyserver refresh failed: %s\n"),gpg_strerror (rc));
+          {
+            write_status_failure ("refresh-keys", rc);
+            log_error (_("keyserver refresh failed: %s\n"),gpg_strerror (rc));
+          }
        free_strlist(sl);
        break;
 
@@ -3949,7 +4233,10 @@ main (int argc, char **argv)
            append_to_strlist2( &sl, *argv, utf8_strings );
        rc = keyserver_fetch (ctrl, sl);
        if(rc)
-         log_error("key fetch failed: %s\n",gpg_strerror (rc));
+          {
+            write_status_failure ("fetch-keys", rc);
+            log_error ("key fetch failed: %s\n",gpg_strerror (rc));
+          }
        free_strlist(sl);
        break;
 
@@ -3957,7 +4244,12 @@ main (int argc, char **argv)
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
-       export_seckeys (ctrl, sl);
+        {
+          export_stats_t stats = export_new_stats ();
+          export_seckeys (ctrl, sl, stats);
+          export_print_stats (stats);
+          export_release_stats (stats);
+        }
        free_strlist(sl);
        break;
 
@@ -3965,7 +4257,12 @@ main (int argc, char **argv)
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
-       export_secsubkeys (ctrl, sl);
+        {
+          export_stats_t stats = export_new_stats ();
+          export_secsubkeys (ctrl, sl, stats);
+          export_print_stats (stats);
+          export_release_stats (stats);
+        }
        free_strlist(sl);
        break;
 
@@ -3978,19 +4275,22 @@ main (int argc, char **argv)
        break;
 
       case aDesigRevoke:
-       if( argc != 1 )
-           wrong_args("--desig-revoke user-id");
-       username =  make_username(*argv);
-       gen_desig_revoke( username, locusr );
-       xfree( username );
+       if (argc != 1)
+           wrong_args ("--desig-revoke user-id");
+       username = make_username (*argv);
+       gen_desig_revoke (ctrl, username, locusr);
+       xfree (username);
        break;
 
       case aDeArmor:
        if( argc > 1 )
            wrong_args("--dearmor [file]");
-       rc = dearmor_file( argc? *argv: NULL );
+       rc = dearmor_file( argc? *argv: NULL, -1 );
        if( rc )
-           log_error(_("dearmoring failed: %s\n"), gpg_strerror (rc));
+          {
+            write_status_failure ("dearmor", rc);
+            log_error (_("dearmoring failed: %s\n"), gpg_strerror (rc));
+          }
        break;
 
       case aEnArmor:
@@ -3998,7 +4298,10 @@ main (int argc, char **argv)
            wrong_args("--enarmor [file]");
        rc = enarmor_file( argc? *argv: NULL );
        if( rc )
-           log_error(_("enarmoring failed: %s\n"), gpg_strerror (rc));
+          {
+            write_status_failure ("enarmor", rc);
+           log_error (_("enarmoring failed: %s\n"), gpg_strerror (rc));
+          }
        break;
 
 
@@ -4020,7 +4323,7 @@ main (int argc, char **argv)
                mpi_print (es_stdout, generate_elg_prime(
                                             1, atoi(argv[1]),
                                             atoi(argv[2]), NULL,&factors ), 1);
-               putchar('\n');
+               es_putc ('\n', es_stdout);
                mpi_print (es_stdout, factors[0], 1 ); /* print q */
            }
            else if( mode == 4 && argc == 3 ) {
@@ -4028,13 +4331,13 @@ main (int argc, char **argv)
                mpi_print (es_stdout, generate_elg_prime(
                                                 0, atoi(argv[1]),
                                                 atoi(argv[2]), g, NULL ), 1);
-               putchar('\n');
+               es_putc ('\n', es_stdout);
                mpi_print (es_stdout, g, 1 );
                mpi_free (g);
            }
            else
                wrong_args("--gen-prime mode bits [qbits] ");
-           putchar('\n');
+           es_putc ('\n', es_stdout);
        }
 #endif
         wrong_args("--gen-prime not yet supported ");
@@ -4063,21 +4366,21 @@ main (int argc, char **argv)
 #endif
                 if (opt.armor) {
                     char *tmp = make_radix64_string (p, n);
-                    fputs (tmp, stdout);
+                    es_fputs (tmp, es_stdout);
                     xfree (tmp);
                     if (n%3 == 1)
-                      putchar ('=');
+                      es_putc ('=', es_stdout);
                     if (n%3)
-                      putchar ('=');
+                      es_putc ('=', es_stdout);
                 } else {
-                    fwrite( p, n, 1, stdout );
+                    es_fwrite( p, n, 1, es_stdout );
                 }
                xfree(p);
                if( !endless )
                    count -= n;
            }
             if (opt.armor)
-                putchar ('\n');
+              es_putc ('\n', es_stdout);
        }
        break;
 
@@ -4114,10 +4417,10 @@ main (int argc, char **argv)
 #ifndef NO_TRUST_MODELS
       case aListTrustDB:
        if( !argc )
-           list_trustdb(NULL);
+          list_trustdb (es_stdout, NULL);
        else {
            for( ; argc; argc--, argv++ )
-               list_trustdb( *argv );
+              list_trustdb (es_stdout, *argv );
        }
        break;
 
@@ -4190,7 +4493,7 @@ main (int argc, char **argv)
         else if (argc == 1)
             change_pin (atoi (*argv),1);
         else
-        wrong_args ("--change-pin [no]");
+            wrong_args ("--change-pin [no]");
         break;
 #endif /* ENABLE_CARD_SUPPORT*/
 
@@ -4202,6 +4505,92 @@ main (int argc, char **argv)
        }
        break;
 
+      case aListGcryptConfig:
+        /* Fixme: It would be nice to integrate that with
+           --list-config but unfortunately there is no way yet to have
+           libgcrypt print it to an estream for further parsing.  */
+        gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
+        break;
+
+      case aTOFUPolicy:
+#ifdef USE_TOFU
+       {
+         int policy;
+         int i;
+         KEYDB_HANDLE hd;
+
+         if (argc < 2)
+           wrong_args ("--tofu-policy POLICY KEYID [KEYID...]");
+
+         policy = parse_tofu_policy (argv[0]);
+
+         hd = keydb_new ();
+         if (! hd)
+            g10_exit (1);
+
+         for (i = 1; i < argc; i ++)
+           {
+             KEYDB_SEARCH_DESC desc;
+             kbnode_t kb;
+
+             rc = classify_user_id (argv[i], &desc, 0);
+             if (rc)
+               {
+                 log_error (_("error parsing key specification '%s': %s\n"),
+                             argv[i], gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             if (! (desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
+                    || desc.mode == KEYDB_SEARCH_MODE_LONG_KID
+                    || desc.mode == KEYDB_SEARCH_MODE_FPR16
+                    || desc.mode == KEYDB_SEARCH_MODE_FPR20
+                    || desc.mode == KEYDB_SEARCH_MODE_FPR
+                    || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP))
+               {
+                 log_error (_("'%s' does not appear to be a valid"
+                              " key ID, fingerprint or keygrip\n"),
+                            argv[i]);
+                 g10_exit (1);
+               }
+
+             rc = keydb_search_reset (hd);
+             if (rc)
+               {
+                  /* This should not happen, thus no need to tranalate
+                     the string.  */
+                  log_error ("keydb_search_reset failed: %s\n",
+                             gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             rc = keydb_search (hd, &desc, 1, NULL);
+             if (rc)
+               {
+                 log_error (_("key \"%s\" not found: %s\n"), argv[i],
+                             gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             rc = keydb_get_keyblock (hd, &kb);
+             if (rc)
+               {
+                 log_error (_("error reading keyblock: %s\n"),
+                             gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             merge_keys_and_selfsig (kb);
+             if (tofu_set_policy (kb, policy))
+               g10_exit (1);
+           }
+
+         keydb_release (hd);
+
+       }
+#endif /*USE_TOFU*/
+       break;
+
       case aListPackets:
        opt.list_packets=2;
       default:
@@ -4237,7 +4626,11 @@ main (int argc, char **argv)
            }
            rc = proc_packets (ctrl, NULL, a );
            if( rc )
-               log_error("processing message failed: %s\n", gpg_strerror (rc));
+              {
+                write_status_failure ("-", rc);
+                log_error ("processing message failed: %s\n",
+                           gpg_strerror (rc));
+              }
            iobuf_close(a);
        }
        break;
@@ -4268,8 +4661,10 @@ g10_exit( int rc )
   gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
   if (DBG_CLOCK)
     log_clock ("stop");
+
   if ( (opt.debug & DBG_MEMSTAT_VALUE) )
     {
+      keydb_dump_stats ();
       gcry_control (GCRYCTL_DUMP_MEMORY_STATS);
       gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
     }
@@ -4297,7 +4692,7 @@ print_hex (gcry_md_hd_t md, int algo, const char *fname)
 
   if (indent>40)
     {
-      printf("\n");
+      es_printf ("\n");
       indent=0;
     }
 
@@ -4395,24 +4790,22 @@ print_hashline( gcry_md_hd_t md, int algo, const char *fname )
 static void
 print_mds( const char *fname, int algo )
 {
-  FILE *fp;
+  estream_t fp;
   char buf[1024];
   size_t n;
   gcry_md_hd_t md;
 
   if (!fname)
     {
-      fp = stdin;
-#ifdef HAVE_DOSISH_SYSTEM
-      setmode ( fileno(fp) , O_BINARY );
-#endif
+      fp = es_stdin;
+      es_set_binary (fp);
     }
   else
     {
-      fp = fopen (fname, "rb" );
-      if (fp && is_secured_file (fileno (fp)))
+      fp = es_fopen (fname, "rb" );
+      if (fp && is_secured_file (es_fileno (fp)))
         {
-          fclose (fp);
+          es_fclose (fp);
           fp = NULL;
           gpg_err_set_errno (EPERM);
         }
@@ -4443,10 +4836,10 @@ print_mds( const char *fname, int algo )
         gcry_md_enable (md, GCRY_MD_SHA512);
     }
 
-  while ((n=fread (buf, 1, DIM(buf), fp)))
+  while ((n=es_fread (buf, 1, DIM(buf), fp)))
     gcry_md_write (md, buf, n);
 
-  if (ferror(fp))
+  if (es_ferror(fp))
     log_error ("%s: %s\n", fname?fname:"[stdin]", strerror(errno));
   else
     {
@@ -4496,8 +4889,8 @@ print_mds( const char *fname, int algo )
     }
   gcry_md_close (md);
 
-  if (fp != stdin)
-    fclose (fp);
+  if (fp != es_stdin)
+    es_fclose (fp);
 }