scd: Implement socket redirection.
[gnupg.git] / sm / gpgsm.c
index d3be015..3398d17 100644 (file)
@@ -1,12 +1,12 @@
-/* gpgsm.c - GnuPG for S/MIME 
- * Copyright (C) 2001, 2002, 2003, 2004, 2005,
- *               2006, 2007  Free Software Foundation, Inc.
+/* gpgsm.c - GnuPG for S/MIME
+ * Copyright (C) 2001-2008, 2010  Free Software Foundation, Inc.
+ * Copyright (C) 2001-2008, 2010  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 2 of the License, or
+ * 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,
@@ -15,9 +15,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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -38,6 +36,9 @@
 #include "i18n.h"
 #include "keydb.h"
 #include "sysutils.h"
+#include "gc-opt-flags.h"
+#include "asshelp.h"
+#include "../common/init.h"
 
 
 #ifndef O_BINARY
@@ -51,7 +52,6 @@ enum cmd_and_opt_values {
   aSym         = 'c',
   aDecrypt     = 'd',
   aEncr                = 'e',
-  oInteractive  = 'i',
   aListKeys    = 'k',
   aListSecretKeys = 'K',
   oDryRun      = 'n',
@@ -59,32 +59,24 @@ enum cmd_and_opt_values {
   oQuiet       = 'q',
   oRecipient   = 'r',
   aSign                = 's',
-  oTextmodeShort= 't',
   oUser                = 'u',
   oVerbose     = 'v',
-  oCompress    = 'z',
-  oNotation    = 'N',
   oBatch       = 500,
   aClearsign,
-  aStore,
   aKeygen,
   aSignEncr,
-  aSignKey,
-  aLSignKey,
-  aListPackets,
-  aEditKey,
   aDeleteKey,
   aImport,
   aVerify,
-  aVerifyFiles,
   aListExternalKeys,
   aListChain,
   aSendKeys,
   aRecvKeys,
   aExport,
   aExportSecretKeyP12,
-  aCheckKeys, /* nyi */
-  aServer,                        
+  aExportSecretKeyP8,
+  aExportSecretKeyRaw,
+  aServer,
   aLearnCard,
   aCallDirmngr,
   aCallProtectTool,
@@ -96,6 +88,7 @@ enum cmd_and_opt_values {
   aDumpSecretKeys,
   aDumpExternalKeys,
   aKeydbClearSomeCertFlags,
+  aFingerprint,
 
   oOptions,
   oDebug,
@@ -109,6 +102,8 @@ enum cmd_and_opt_values {
   oFixedPassphrase,
   oLogFile,
   oNoLogFile,
+  oAuditLog,
+  oHtmlAuditLog,
 
   oEnableSpecialFilenames,
 
@@ -118,9 +113,11 @@ enum cmd_and_opt_values {
   oTTYtype,
   oLCctype,
   oLCmessages,
+  oXauthority,
 
   oPreferSystemDirmngr,
   oDirmngrProgram,
+  oDisableDirmngr,
   oProtectToolProgram,
   oFakedSystemTime,
 
@@ -147,36 +144,23 @@ enum cmd_and_opt_values {
   oDisablePolicyChecks,
   oEnablePolicyChecks,
   oAutoIssuerKeyRetrieve,
-  
 
-  oTextmode,
-  oFingerprint,
   oWithFingerprint,
   oWithMD5Fingerprint,
+  oWithKeygrip,
+  oWithSecret,
   oAnswerYes,
   oAnswerNo,
   oKeyring,
-  oSecretKeyring,
   oDefaultKey,
   oDefRecipient,
   oDefRecipientSelf,
   oNoDefRecipient,
   oStatusFD,
-  oNoComment,
-  oNoVersion,
-  oEmitVersion,
-  oCompletesNeeded,
-  oMarginalsNeeded,
-  oMaxCertDepth,
-  oLoadExtension,
-  oRFC1991,
-  oOpenPGP,
   oCipherAlgo,
   oDigestAlgo,
-  oCompressAlgo,
-  oCommandFD,
+  oExtraDigestAlgo,
   oNoVerbose,
-  oTrustDBName,
   oNoSecmemWarn,
   oNoDefKeyring,
   oNoGreeting,
@@ -189,275 +173,242 @@ enum cmd_and_opt_values {
   oWithValidation,
   oWithEphemeralKeys,
   oSkipVerify,
-  oCompressKeys,
-  oCompressSigs,
-  oAlwaysTrust,
-  oRunAsShmCP,
-  oSetFilename,
-  oSetPolicyURL,
-  oUseEmbeddedFilename,
-  oComment,
-  oDefaultComment,
-  oThrowKeyid,
-  oForceV3Sigs,
-  oForceMDC,
-  oS2KMode,
-  oS2KDigest,
-  oS2KCipher,
-  oCharset,
-  oNotDashEscaped,
-  oEscapeFrom,
-  oLockOnce,
-  oLockMultiple,
-  oLockNever,
+  oValidationModel,
   oKeyServer,
   oEncryptTo,
   oNoEncryptTo,
   oLoggerFD,
-  oUtf8Strings,
-  oNoUtf8Strings,
   oDisableCipherAlgo,
   oDisablePubkeyAlgo,
-  oAllowNonSelfsignedUID,
-  oAllowFreeformUID,
-  oNoLiteral,
-  oSetFilesize,
-  oHonorHttpProxy,
-  oFastListMode,
-  oListOnly,
   oIgnoreTimeConflict,
   oNoRandomSeedFile,
-  oNoAutoKeyRetrieve,
-  oUseAgent,
-  oMergeOnly,
-  oTryAllSecrets,
-  oTrustedKey,
-  oEmuMDEncodeBug,
-  aDummy
+  oNoCommonCertsImport,
+  oIgnoreCertExtension,
+  oNoAutostart
  };
 
 
 static ARGPARSE_OPTS opts[] = {
 
-    { 300, NULL, 0, N_("@Commands:\n ") },
-
-    { aSign, "sign",      256, N_("|[FILE]|make a signature")},
-    { aClearsign, "clearsign", 256, N_("|[FILE]|make a clear text signature") },
-    { aDetachedSign, "detach-sign", 256, N_("make a detached signature")},
-    { aEncr, "encrypt",   256, N_("encrypt data")},
-    { aSym, "symmetric", 256, N_("encryption only with symmetric cipher")},
-    { aDecrypt, "decrypt",   256, N_("decrypt data (default)")},
-    { aVerify, "verify"   , 256, N_("verify a signature")},
-    { aVerifyFiles, "verify-files" , 256, "@" },
-    { aListKeys, "list-keys", 256, N_("list keys")},
-    { aListExternalKeys, "list-external-keys", 256, N_("list external keys")},
-    { aListSecretKeys, "list-secret-keys", 256, N_("list secret keys")},
-    { aListChain,   "list-chain",  256, N_("list certificate chain")}, 
-    { oFingerprint, "fingerprint", 256, N_("list keys and fingerprints")},
-    { aKeygen,    "gen-key",  256, "@" },
-    { aDeleteKey, "delete-key",256, N_("remove key from the public keyring")},
-    { aSendKeys, "send-keys"     , 256, N_("export keys to a key server") },
-    { aRecvKeys, "recv-keys"     , 256, N_("import keys from a key server") },
-    { aImport, "import",      256     , N_("import certificates")},
-    { aExport, "export",      256     , N_("export certificates")},
-    { aLearnCard, "learn-card", 256 ,N_("register a smartcard")},
-    { aServer, "server",      256, N_("run in server mode")},
-    { aCallDirmngr, "call-dirmngr", 256, N_("pass a command to the dirmngr")},
-    { aCallProtectTool, "call-protect-tool", 256,
-                                   N_("invoke gpg-protect-tool")},
-    { aPasswd, "passwd",      256, N_("change a passphrase")},
-    { aGPGConfList, "gpgconf-list", 256, "@" },
-    { aGPGConfTest, "gpgconf-test", 256, "@" },
-
-    { aDumpKeys, "dump-cert", 256, "@"},
-    { aDumpKeys, "dump-keys", 256, "@"},
-    { aDumpChain, "dump-chain", 256, "@"},
-    { aDumpExternalKeys, "dump-external-keys", 256, "@"},
-    { aDumpSecretKeys, "dump-secret-keys", 256, "@"},
-    { aKeydbClearSomeCertFlags, "keydb-clear-some-cert-flags", 256, "@"},
-
-    { 301, NULL, 0, N_("@\nOptions:\n ") },
-
-    { oArmor, "armor",     0, N_("create ascii armored output")},
-    { oArmor, "armour",    0, "@" },
-    { oBase64, "base64",    0, N_("create base-64 encoded output")},
-
-    { oP12Charset, "p12-charset", 2, "@" },
-    
-    { oAssumeArmor,  "assume-armor", 0, N_("assume input is in PEM format")},
-    { oAssumeBase64, "assume-base64", 0,
-                                      N_("assume input is in base-64 format")},
-    { oAssumeBinary, "assume-binary", 0,
-                                      N_("assume input is in binary format")},
-
-    { oRecipient, "recipient", 2, N_("|NAME|encrypt for NAME")},
-
-    { oPreferSystemDirmngr,"prefer-system-dirmngr", 0,
-      N_("use system's dirmngr if available")},
-    { oDisableCRLChecks, "disable-crl-checks", 0, N_("never consult a CRL")},
-    { oEnableCRLChecks, "enable-crl-checks", 0, "@"},
-    { oDisableTrustedCertCRLCheck, "disable-trusted-cert-crl-check", 0, "@"},
-    { oEnableTrustedCertCRLCheck, "enable-trusted-cert-crl-check", 0, "@"},
-    { oForceCRLRefresh, "force-crl-refresh", 0, "@"},
-
-    { oDisableOCSP, "disable-ocsp", 0, "@" },
-    { oEnableOCSP,  "enable-ocsp", 0, N_("check validity using OCSP")},
-
-    { oIncludeCerts, "include-certs", 1,
-                                 N_("|N|number of certificates to include") },
-
-    { oPolicyFile, "policy-file", 2,
-                    N_("|FILE|take policy information from FILE") },
-
-    { oDisablePolicyChecks, "disable-policy-checks", 0,
-                           N_("do not check certificate policies")},
-    { oEnablePolicyChecks, "enable-policy-checks", 0, "@"},
-
-    { oAutoIssuerKeyRetrieve, "auto-issuer-key-retrieve", 0, 
-      N_("fetch missing issuer certificates")},
-
-#if 0
-    { oDefRecipient, "default-recipient" ,2,
-                                 N_("|NAME|use NAME as default recipient")},
-    { oDefRecipientSelf, "default-recipient-self" ,0,
-                               N_("use the default key as default recipient")},
-    { oNoDefRecipient, "no-default-recipient", 0, "@" },
-#endif
-    { oEncryptTo, "encrypt-to", 2, "@" },
-    { oNoEncryptTo, "no-encrypt-to", 0, "@" },
-
-    { oUser, "local-user",2, N_("use this user-id to sign or decrypt")},
-
-#if 0
-    { oCompress, NULL,       1, N_("|N|set compress level N (0 disables)") },
-    { oTextmodeShort, NULL,   0, "@"},
-    { oTextmode, "textmode",  0, N_("use canonical text mode")},
-#endif
-
-    { oOutput, "output",    2, N_("use as output file")},
-    { oVerbose, "verbose",   0, N_("verbose") },
-    { oQuiet,  "quiet",   0, N_("be somewhat more quiet") },
-    { oNoTTY, "no-tty", 0, N_("don't use the terminal at all") },
-    { oLogFile, "log-file"   ,2, N_("use a log file for the server")},
-    { oNoLogFile, "no-log-file" ,0, "@"},
-#if 0
-    { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") },
-    { oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") },
-#endif
-    { oDryRun, "dry-run",   0, N_("do not make any changes") },
-  /*{ oInteractive, "interactive", 0, N_("prompt before overwriting") }, */
-    /*{ oUseAgent, "use-agent",0, N_("use the gpg-agent")},*/
-    { oBatch, "batch",     0, N_("batch mode: never ask")},
-    { oAnswerYes, "yes",       0, N_("assume yes on most questions")},
-    { oAnswerNo,  "no",        0, N_("assume no on most questions")},
-
-    { oKeyring, "keyring"   ,2, N_("add this keyring to the list of keyrings")},
-    { oSecretKeyring, "secret-keyring" ,2, N_("add this secret keyring to the list")},
-    { oDefaultKey, "default-key" ,2, N_("|NAME|use NAME as default secret key")},
-    { oKeyServer, "keyserver",2, N_("|HOST|use this keyserver to lookup keys")},
-    { oCharset, "charset"   , 2, N_("|NAME|set terminal charset to NAME") },
-    { oOptions, "options"   , 2, N_("read options from file")},
-
-    { oDebug, "debug"     ,4|16, "@"},
-    { oDebugLevel, "debug-level" ,2, N_("|LEVEL|set the debugging level to LEVEL")},
-    { oDebugAll, "debug-all" ,0, "@"},
-    { oDebugNone, "debug-none" ,0, "@"},
-    { oDebugWait, "debug-wait" ,1, "@"},
-    { oDebugAllowCoreDump, "debug-allow-core-dump", 0, "@" },
-    { oDebugNoChainValidation, "debug-no-chain-validation", 0, "@"},
-    { oDebugIgnoreExpiration,  "debug-ignore-expiration", 0, "@"},
-    { oFixedPassphrase,        "fixed-passphrase", 2, "@"},
-    { oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
-    { aDummy, "no-comment", 0,   "@"},
-    { aDummy, "completes-needed", 1, "@"},
-    { aDummy, "marginals-needed", 1, "@"},
-    { oMaxCertDepth,   "max-cert-depth", 1, "@" },
-    { aDummy, "trusted-key", 2, "@"},
-    { oLoadExtension, "load-extension" ,2,
-      N_("|FILE|load extension module FILE")},
-    { aDummy, "rfc1991",   0, "@"},
-    { aDummy, "openpgp",   0, "@"},
-    { aDummy, "s2k-mode",  1, "@"},
-    { aDummy, "s2k-digest-algo",2, "@"},
-    { aDummy, "s2k-cipher-algo",2, "@"},
-    { oCipherAlgo, "cipher-algo", 2 , N_("|NAME|use cipher algorithm NAME")},
-    { oDigestAlgo, "digest-algo", 2 ,
-      N_("|NAME|use message digest algorithm NAME")},
-#if 0
-    { oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")},
-#endif
-    { aDummy, "throw-keyid", 0, "@"},
-    { aDummy, "notation-data", 2, "@"},
-    { aExportSecretKeyP12, "export-secret-key-p12", 256, "@"}, 
-    
-
-    { 302, NULL, 0, N_(
+  ARGPARSE_group (300, N_("@Commands:\n ")),
+
+  ARGPARSE_c (aSign, "sign", N_("make a signature")),
+/*ARGPARSE_c (aClearsign, "clearsign", N_("make a clear text signature") ),*/
+  ARGPARSE_c (aDetachedSign, "detach-sign", N_("make a detached signature")),
+  ARGPARSE_c (aEncr, "encrypt", N_("encrypt data")),
+/*ARGPARSE_c (aSym, "symmetric", N_("encryption only with symmetric cipher")),*/
+  ARGPARSE_c (aDecrypt, "decrypt", N_("decrypt data (default)")),
+  ARGPARSE_c (aVerify, "verify",  N_("verify a signature")),
+  ARGPARSE_c (aListKeys, "list-keys", N_("list keys")),
+  ARGPARSE_c (aListExternalKeys, "list-external-keys",
+              N_("list external keys")),
+  ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")),
+  ARGPARSE_c (aListChain,   "list-chain",  N_("list certificate chain")),
+  ARGPARSE_c (aFingerprint, "fingerprint", N_("list keys and fingerprints")),
+  ARGPARSE_c (aKeygen, "gen-key", N_("generate a new key pair")),
+  ARGPARSE_c (aDeleteKey, "delete-keys",
+              N_("remove keys from the public keyring")),
+/*ARGPARSE_c (aSendKeys, "send-keys", N_("export keys to a key server")),*/
+/*ARGPARSE_c (aRecvKeys, "recv-keys", N_("import keys from a key server")),*/
+  ARGPARSE_c (aImport, "import", N_("import certificates")),
+  ARGPARSE_c (aExport, "export", N_("export certificates")),
+
+  /* We use -raw and not -p1 for pkcs#1 secret key export so that it
+     won't accidently be used in case -p12 was intended.  */
+  ARGPARSE_c (aExportSecretKeyP12, "export-secret-key-p12", "@"),
+  ARGPARSE_c (aExportSecretKeyP8,  "export-secret-key-p8", "@"),
+  ARGPARSE_c (aExportSecretKeyRaw, "export-secret-key-raw", "@"),
+
+  ARGPARSE_c (aLearnCard, "learn-card", N_("register a smartcard")),
+  ARGPARSE_c (aServer, "server", N_("run in server mode")),
+  ARGPARSE_c (aCallDirmngr, "call-dirmngr",
+              N_("pass a command to the dirmngr")),
+  ARGPARSE_c (aCallProtectTool, "call-protect-tool",
+              N_("invoke gpg-protect-tool")),
+  ARGPARSE_c (aPasswd, "passwd", N_("change a passphrase")),
+  ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
+  ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
+
+  ARGPARSE_c (aDumpKeys, "dump-cert", "@"),
+  ARGPARSE_c (aDumpKeys, "dump-keys", "@"),
+  ARGPARSE_c (aDumpChain, "dump-chain", "@"),
+  ARGPARSE_c (aDumpExternalKeys, "dump-external-keys", "@"),
+  ARGPARSE_c (aDumpSecretKeys, "dump-secret-keys", "@"),
+  ARGPARSE_c (aKeydbClearSomeCertFlags, "keydb-clear-some-cert-flags", "@"),
+
+  ARGPARSE_group (301, N_("@\nOptions:\n ")),
+
+  ARGPARSE_s_n (oArmor, "armor", N_("create ascii armored output")),
+  ARGPARSE_s_n (oArmor, "armour", "@"),
+  ARGPARSE_s_n (oBase64, "base64", N_("create base-64 encoded output")),
+
+  ARGPARSE_s_s (oP12Charset, "p12-charset", "@"),
+
+  ARGPARSE_s_n (oAssumeArmor, "assume-armor",
+                N_("assume input is in PEM format")),
+  ARGPARSE_s_n (oAssumeBase64, "assume-base64",
+                N_("assume input is in base-64 format")),
+  ARGPARSE_s_n (oAssumeBinary, "assume-binary",
+                N_("assume input is in binary format")),
+
+  ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
+
+  ARGPARSE_s_n (oPreferSystemDirmngr,"prefer-system-dirmngr", "@"),
+
+  ARGPARSE_s_n (oDisableCRLChecks, "disable-crl-checks",
+                N_("never consult a CRL")),
+  ARGPARSE_s_n (oEnableCRLChecks, "enable-crl-checks", "@"),
+  ARGPARSE_s_n (oDisableTrustedCertCRLCheck,
+                "disable-trusted-cert-crl-check", "@"),
+  ARGPARSE_s_n (oEnableTrustedCertCRLCheck,
+                "enable-trusted-cert-crl-check", "@"),
+
+  ARGPARSE_s_n (oForceCRLRefresh, "force-crl-refresh", "@"),
+
+  ARGPARSE_s_n (oDisableOCSP, "disable-ocsp", "@"),
+  ARGPARSE_s_n (oEnableOCSP,  "enable-ocsp", N_("check validity using OCSP")),
+
+  ARGPARSE_s_s (oValidationModel, "validation-model", "@"),
+
+  ARGPARSE_s_i (oIncludeCerts, "include-certs",
+                N_("|N|number of certificates to include") ),
+
+  ARGPARSE_s_s (oPolicyFile, "policy-file",
+                N_("|FILE|take policy information from FILE")),
+
+  ARGPARSE_s_n (oDisablePolicyChecks, "disable-policy-checks",
+                N_("do not check certificate policies")),
+  ARGPARSE_s_n (oEnablePolicyChecks, "enable-policy-checks", "@"),
+
+  ARGPARSE_s_n (oAutoIssuerKeyRetrieve, "auto-issuer-key-retrieve",
+                N_("fetch missing issuer certificates")),
+
+  ARGPARSE_s_s (oEncryptTo, "encrypt-to", "@"),
+  ARGPARSE_s_n (oNoEncryptTo, "no-encrypt-to", "@"),
+
+  ARGPARSE_s_s (oUser, "local-user",
+                N_("|USER-ID|use USER-ID to sign or decrypt")),
+
+  ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
+  ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
+  ARGPARSE_s_n (oQuiet,        "quiet",  N_("be somewhat more quiet")),
+  ARGPARSE_s_n (oNoTTY, "no-tty", N_("don't use the terminal at all")),
+  ARGPARSE_s_s (oLogFile, "log-file",
+                N_("|FILE|write a server mode log to FILE")),
+  ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
+  ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
+
+  ARGPARSE_s_s (oAuditLog, "audit-log",
+                N_("|FILE|write an audit log to FILE")),
+  ARGPARSE_s_s (oHtmlAuditLog, "html-audit-log", "@"),
+  ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
+  ARGPARSE_s_n (oBatch, "batch", N_("batch mode: never ask")),
+  ARGPARSE_s_n (oAnswerYes, "yes", N_("assume yes on most questions")),
+  ARGPARSE_s_n (oAnswerNo,  "no",  N_("assume no on most questions")),
+
+  ARGPARSE_s_s (oKeyring, "keyring",
+                N_("|FILE|add keyring to the list of keyrings")),
+
+  ARGPARSE_s_s (oDefaultKey, "default-key",
+                N_("|USER-ID|use USER-ID as default secret key")),
+
+  /* Not yet used: */
+  /*   ARGPARSE_s_s (oDefRecipient, "default-recipient", */
+  /*                  N_("|NAME|use NAME as default recipient")), */
+  /*   ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", */
+  /*                  N_("use the default key as default recipient")), */
+  /*   ARGPARSE_s_n (oNoDefRecipient, "no-default-recipient", "@"), */
+
+  ARGPARSE_s_s (oKeyServer, "keyserver",
+                N_("|SPEC|use this keyserver to lookup keys")),
+  ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
+
+  ARGPARSE_p_u (oDebug, "debug", "@"),
+  ARGPARSE_s_s (oDebugLevel, "debug-level",
+                N_("|LEVEL|set the debugging level to LEVEL")),
+  ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
+  ARGPARSE_s_n (oDebugNone, "debug-none", "@"),
+  ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
+  ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
+  ARGPARSE_s_n (oDebugNoChainValidation, "debug-no-chain-validation", "@"),
+  ARGPARSE_s_n (oDebugIgnoreExpiration,  "debug-ignore-expiration", "@"),
+  ARGPARSE_s_s (oFixedPassphrase, "fixed-passphrase", "@"),
+
+  ARGPARSE_s_i (oStatusFD, "status-fd",
+                N_("|FD|write status info to this FD")),
+
+  ARGPARSE_s_s (oCipherAlgo, "cipher-algo",
+                N_("|NAME|use cipher algorithm NAME")),
+  ARGPARSE_s_s (oDigestAlgo, "digest-algo",
+                N_("|NAME|use message digest algorithm NAME")),
+  ARGPARSE_s_s (oExtraDigestAlgo, "extra-digest-algo", "@"),
+
+
+  ARGPARSE_group (302, N_(
   "@\n(See the man page for a complete listing of all commands and options)\n"
-                     )},
+  )),
 
-    { 303, NULL, 0, N_("@\nExamples:\n\n"
+  ARGPARSE_group (303, N_("@\nExamples:\n\n"
     " -se -r Bob [file]          sign and encrypt for user Bob\n"
     " --clearsign [file]         make a clear text signature\n"
     " --detach-sign [file]       make a detached signature\n"
     " --list-keys [names]        show keys\n"
-    " --fingerprint [names]      show fingerprints\n"  ) },
-
-  /* hidden options */
-    { oNoVerbose, "no-verbose", 0, "@"},
-
-    { oEnableSpecialFilenames, "enable-special-filenames", 0, "@" },
-
-
-    { oTrustDBName, "trustdb-name", 2, "@" },
-    { oNoSecmemWarn, "no-secmem-warning", 0, "@" }, 
-    { oNoArmor, "no-armor",   0, "@"},
-    { oNoArmor, "no-armour",   0, "@"},
-    { oNoDefKeyring, "no-default-keyring", 0, "@" },
-    { oNoGreeting, "no-greeting", 0, "@" },
-    { oNoOptions, "no-options", 0, "@" }, /* shortcut for --options /dev/null */
-    { oHomedir, "homedir", 2, "@" },   /* defaults to "~/.gnupg" */
-    { oAgentProgram, "agent-program", 2 , "@" },
-    { oDisplay,    "display",     2, "@" },
-    { oTTYname,    "ttyname",     2, "@" },
-    { oTTYtype,    "ttytype",     2, "@" },
-    { oLCctype,    "lc-ctype",    2, "@" },
-    { oLCmessages, "lc-messages", 2, "@" },
-    { oDirmngrProgram, "dirmngr-program", 2 , "@" },
-    { oProtectToolProgram, "protect-tool-program", 2 , "@" },
-    { oFakedSystemTime, "faked-system-time", 4, "@" }, /* (epoch time) */
-
-
-    { oNoBatch, "no-batch", 0, "@" },
-    { oWithColons, "with-colons", 0, "@"},
-    { oWithKeyData,"with-key-data", 0, "@"},
-    { oWithValidation, "with-validation", 0, "@"},
-    { oWithMD5Fingerprint, "with-md5-fingerprint", 0, "@"},
-    { oWithEphemeralKeys,  "with-ephemeral-keys", 0, "@"},
-    { aListKeys, "list-key", 256, "@" },  /* alias */
-    { aListChain, "list-sig", 256, "@" }, /* alias */
-    { aListChain, "list-sigs",256, "@" }, /* alias */
-    { aListChain, "check-sig",256, "@" }, /* alias */
-    { aListChain, "check-sigs",256, "@"}, /* alias */
-    { oSkipVerify, "skip-verify",0, "@" },
-    { oCompressKeys, "compress-keys",0, "@"},
-    { oCompressSigs, "compress-sigs",0, "@"},
-    { oAlwaysTrust, "always-trust", 0, "@"},
-    { oNoVersion, "no-version", 0, "@"},
-    { oLockOnce, "lock-once", 0, "@" },
-    { oLockMultiple, "lock-multiple", 0, "@" },
-    { oLockNever, "lock-never", 0, "@" },
-    { oLoggerFD, "logger-fd",1, "@" },
-    { oWithFingerprint, "with-fingerprint", 0, "@" },
-    { oDisableCipherAlgo,  "disable-cipher-algo", 2, "@" },
-    { oDisablePubkeyAlgo,  "disable-pubkey-algo", 2, "@" },
-    { oHonorHttpProxy,"honor-http-proxy", 0, "@" },
-    { oListOnly, "list-only", 0, "@"},
-    { oIgnoreTimeConflict, "ignore-time-conflict", 0, "@" },
-    { oNoRandomSeedFile,  "no-random-seed-file", 0, "@" },
-{0} };
-
-
-
+    " --fingerprint [names]      show fingerprints\n"  )),
+
+  /* Hidden options. */
+  ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
+  ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
+  ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
+  ARGPARSE_s_n (oNoArmor, "no-armor", "@"),
+  ARGPARSE_s_n (oNoArmor, "no-armour", "@"),
+  ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
+  ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
+  ARGPARSE_s_n (oNoOptions, "no-options", "@"),
+  ARGPARSE_s_s (oHomedir, "homedir", "@"),
+  ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
+  ARGPARSE_s_s (oDisplay,    "display", "@"),
+  ARGPARSE_s_s (oTTYname,    "ttyname", "@"),
+  ARGPARSE_s_s (oTTYtype,    "ttytype", "@"),
+  ARGPARSE_s_s (oLCctype,    "lc-ctype", "@"),
+  ARGPARSE_s_s (oLCmessages, "lc-messages", "@"),
+  ARGPARSE_s_s (oXauthority, "xauthority", "@"),
+  ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
+  ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"),
+  ARGPARSE_s_s (oProtectToolProgram, "protect-tool-program", "@"),
+  ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
+  ARGPARSE_s_n (oNoBatch, "no-batch", "@"),
+  ARGPARSE_s_n (oWithColons, "with-colons", "@"),
+  ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"),
+  ARGPARSE_s_n (oWithValidation, "with-validation", "@"),
+  ARGPARSE_s_n (oWithMD5Fingerprint, "with-md5-fingerprint", "@"),
+  ARGPARSE_s_n (oWithEphemeralKeys,  "with-ephemeral-keys", "@"),
+  ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
+  ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
+  ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
+  ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
+  ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
+  ARGPARSE_s_s (oDisablePubkeyAlgo,  "disable-pubkey-algo", "@"),
+  ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
+  ARGPARSE_s_n (oNoRandomSeedFile,  "no-random-seed-file", "@"),
+  ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"),
+  ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"),
+  ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
+
+  /* Command aliases.  */
+  ARGPARSE_c (aListKeys, "list-key", "@"),
+  ARGPARSE_c (aListChain, "list-sig", "@"),
+  ARGPARSE_c (aListChain, "list-sigs", "@"),
+  ARGPARSE_c (aListChain, "check-sig", "@"),
+  ARGPARSE_c (aListChain, "check-sigs", "@"),
+  ARGPARSE_c (aDeleteKey, "delete-key", "@"),
+
+  ARGPARSE_end ()
+};
+
+
+
+
+/* Global variable to keep an error count. */
 int gpgsm_errors_seen = 0;
 
 /* It is possible that we are currentlu running under setuid permissions */
@@ -470,9 +421,24 @@ static unsigned int debug_value;
 /* Option --enable-special-filenames */
 static int allow_special_filenames;
 
-/* Default value for include-certs. */
-static int default_include_certs = 1; /* Only include the signer's cert. */
+/* Default value for include-certs.  We need an extra macro for
+   gpgconf-list because the variable will be changed by the command
+   line option.
 
+   It is often cumbersome to locate intermediate certificates, thus by
+   default we include all certificates in the chain.  However we leave
+   out the root certificate because that would make it too easy for
+   the recipient to import that root certificate.  A root certificate
+   should be installed only after due checks and thus it won't help to
+   send it along with each message.  */
+#define DEFAULT_INCLUDE_CERTS -2 /* Include all certs but root. */
+static int default_include_certs = DEFAULT_INCLUDE_CERTS;
+
+/* Whether the chain mode shall be used for validation.  */
+static int default_validation_model;
+
+/* The default cipher algo.  */
+#define DEFAULT_CIPHER_ALGO "3DES"  /*des-EDE3-CBC*/
 
 
 static char *build_list (const char *text,
@@ -483,50 +449,117 @@ static void set_cmd (enum cmd_and_opt_values *ret_cmd,
 static void emergency_cleanup (void);
 static int check_special_filename (const char *fname, int for_write);
 static int open_read (const char *filename);
-static FILE *open_fwrite (const char *filename);
+static estream_t open_es_fread (const char *filename, const char *mode);
 static estream_t open_es_fwrite (const char *filename);
 static void run_protect_tool (int argc, char **argv);
 
-
 static int
 our_pk_test_algo (int algo)
 {
-  return 1;
+  switch (algo)
+    {
+    case GCRY_PK_RSA:
+    case GCRY_PK_ECDSA:
+      return gcry_pk_test_algo (algo);
+    default:
+      return 1;
+    }
 }
 
 static int
 our_cipher_test_algo (int algo)
 {
-  return 1;
+  switch (algo)
+    {
+    case GCRY_CIPHER_3DES:
+    case GCRY_CIPHER_AES128:
+    case GCRY_CIPHER_AES192:
+    case GCRY_CIPHER_AES256:
+    case GCRY_CIPHER_SERPENT128:
+    case GCRY_CIPHER_SERPENT192:
+    case GCRY_CIPHER_SERPENT256:
+    case GCRY_CIPHER_SEED:
+    case GCRY_CIPHER_CAMELLIA128:
+    case GCRY_CIPHER_CAMELLIA192:
+    case GCRY_CIPHER_CAMELLIA256:
+      return gcry_cipher_test_algo (algo);
+    default:
+      return 1;
+    }
 }
 
+
 static int
 our_md_test_algo (int algo)
 {
-  return 1;
+  switch (algo)
+    {
+    case GCRY_MD_MD5:
+    case GCRY_MD_SHA1:
+    case GCRY_MD_RMD160:
+    case GCRY_MD_SHA224:
+    case GCRY_MD_SHA256:
+    case GCRY_MD_SHA384:
+    case GCRY_MD_SHA512:
+    case GCRY_MD_WHIRLPOOL:
+      return gcry_md_test_algo (algo);
+    default:
+      return 1;
+    }
 }
 
+
+static char *
+make_libversion (const char *libname, const char *(*getfnc)(const char*))
+{
+  const char *s;
+  char *result;
+
+  if (maybe_setuid)
+    {
+      gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
+      maybe_setuid = 0;
+    }
+  s = getfnc (NULL);
+  result = xmalloc (strlen (libname) + 1 + strlen (s) + 1);
+  strcpy (stpcpy (stpcpy (result, libname), " "), s);
+  return result;
+}
+
+
 static const char *
 my_strusage( int level )
 {
   static char *digests, *pubkeys, *ciphers;
+  static char *ver_gcry, *ver_ksba;
   const char *p;
 
   switch (level)
     {
-    case 11: p = "gpgsm (GnuPG)";
+    case 11: p = "@GPGSM@ (@GNUPG@)";
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
-    case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
-      break;
+    case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
+
     case 1:
-    case 40: p = _("Usage: gpgsm [options] [files] (-h for help)");
+    case 40: p = _("Usage: @GPGSM@ [options] [files] (-h for help)");
       break;
     case 41:
-      p = _("Syntax: gpgsm [options] [files]\n"
-            "sign, check, encrypt or decrypt using the S/MIME protocol\n"
-            "default operation depends on the input data\n");
+      p = _("Syntax: @GPGSM@ [options] [files]\n"
+            "Sign, check, encrypt or decrypt using the S/MIME protocol\n"
+            "Default operation depends on the input data\n");
+      break;
+
+    case 20:
+      if (!ver_gcry)
+        ver_gcry = make_libversion ("libgcrypt", gcry_check_version);
+      p = ver_gcry;
+      break;
+    case 21:
+      if (!ver_ksba)
+        ver_ksba = make_libversion ("libksba", ksba_check_version);
+      p = ver_ksba;
       break;
 
     case 31: p = "\nHome: "; break;
@@ -534,7 +567,7 @@ my_strusage( int level )
     case 33: p = _("\nSupported algorithms:\n"); break;
     case 34:
       if (!ciphers)
-        ciphers = build_list ("Cipher: ", gcry_cipher_algo_name,
+        ciphers = build_list ("Cipher: ", gnupg_cipher_algo_name,
                               our_cipher_test_algo );
       p = ciphers;
       break;
@@ -549,7 +582,7 @@ my_strusage( int level )
         digests = build_list("Hash: ", gcry_md_algo_name, our_md_test_algo );
       p = digests;
       break;
-      
+
     default: p = NULL; break;
     }
   return p;
@@ -562,17 +595,17 @@ build_list (const char *text, const char * (*mapf)(int), int (*chkf)(int))
   int i;
   size_t n=strlen(text)+2;
   char *list, *p;
-  
+
   if (maybe_setuid) {
     gcry_control (GCRYCTL_DROP_PRIVS); /* drop setuid */
   }
 
-  for (i=1; i < 110; i++ )
+  for (i=1; i < 400; i++ )
     if (!chkf(i))
       n += strlen(mapf(i)) + 2;
   list = xmalloc (21 + n);
   *list = 0;
-  for (p=NULL, i=1; i < 110; i++)
+  for (p=NULL, i=1; i < 400; i++)
     {
       if (!chkf(i))
         {
@@ -595,6 +628,8 @@ set_binary (FILE *fp)
 {
 #ifdef HAVE_DOSISH_SYSTEM
   setmode (fileno (fp), O_BINARY);
+#else
+  (void)fp;
 #endif
 }
 
@@ -603,13 +638,23 @@ set_binary (FILE *fp)
 static void
 wrong_args (const char *text)
 {
-  fputs (_("usage: gpgsm [options] "), stderr);
-  fputs (text, stderr);
-  putc ('\n', stderr);
+  fprintf (stderr, _("usage: %s [options] %s\n"), GPGSM_NAME, text);
   gpgsm_exit (2);
 }
 
 
+static void
+set_opt_session_env (const char *name, const char *value)
+{
+  gpg_error_t err;
+
+  err = session_env_setenv (opt.session_env, name, value);
+  if (err)
+    log_fatal ("error setting session environment: %s\n",
+               gpg_strerror (err));
+}
+
+
 /* Setup the debugging.  With a DEBUG_LEVEL of NULL only the active
    debug flags are propagated to the subsystems.  With DEBUG_LEVEL
    set, a specific set of debug flags is set; and individual debugging
@@ -617,23 +662,34 @@ wrong_args (const char *text)
 static void
 set_debug (void)
 {
+  int numok = (debug_level && digitp (debug_level));
+  int numlvl = numok? atoi (debug_level) : 0;
+
   if (!debug_level)
     ;
-  else if (!strcmp (debug_level, "none"))
+  else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
     opt.debug = 0;
-  else if (!strcmp (debug_level, "basic"))
+  else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
     opt.debug = DBG_ASSUAN_VALUE;
-  else if (!strcmp (debug_level, "advanced"))
+  else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
     opt.debug = DBG_ASSUAN_VALUE|DBG_X509_VALUE;
-  else if (!strcmp (debug_level, "expert"))
+  else if (!strcmp (debug_level, "expert")  || (numok && numlvl <= 8))
     opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE
                  |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
-  else if (!strcmp (debug_level, "guru"))
-    opt.debug = ~0;
+  else if (!strcmp (debug_level, "guru") || numok)
+    {
+      opt.debug = ~0;
+      /* Unless the "guru" string has been used we don't want to allow
+         hashing debugging.  The rationale is that people tend to
+         select the highest debug value and would then clutter their
+         disk with debug files which may reveal confidential data.  */
+      if (numok)
+        opt.debug &= ~(DBG_HASHING_VALUE);
+    }
   else
     {
-      log_error (_("invalid debug-level `%s' given\n"), debug_level);
-      gpgsm_exit(2);
+      log_error (_("invalid debug-level '%s' given\n"), debug_level);
+      gpgsm_exit (2);
     }
 
   opt.debug |= debug_value;
@@ -648,8 +704,19 @@ set_debug (void)
   if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 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\n",
+              (opt.debug & DBG_X509_VALUE   )? " x509":"",
+              (opt.debug & DBG_MPI_VALUE    )? " mpi":"",
+              (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
+              (opt.debug & DBG_MEMORY_VALUE )? " memory":"",
+              (opt.debug & DBG_CACHE_VALUE  )? " cache":"",
+              (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
+              (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
+              (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"" );
 }
+
 
 
 static void
@@ -666,7 +733,7 @@ set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
   else if ( (cmd == aSign && new_cmd == aClearsign)
             || (cmd == aClearsign && new_cmd == aSign) )
     cmd = aClearsign;
-  else 
+  else
     {
       log_error(_("conflicting commands\n"));
       gpgsm_exit(2);
@@ -679,35 +746,134 @@ set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
 /* Helper to add recipients to a list. */
 static void
 do_add_recipient (ctrl_t ctrl, const char *name,
-                  certlist_t *recplist, int is_encrypt_to)
+                  certlist_t *recplist, int is_encrypt_to, int recp_required)
 {
   int rc = gpgsm_add_to_certlist (ctrl, name, 0, recplist, is_encrypt_to);
   if (rc)
     {
-      log_error (_("can't encrypt to `%s': %s\n"), name, gpg_strerror (rc));
-      gpgsm_status2 (ctrl, STATUS_INV_RECP,
-                     gpg_err_code (rc) == -1?                         "1":
-                     gpg_err_code (rc) == GPG_ERR_NO_PUBKEY?          "1":
-                     gpg_err_code (rc) == GPG_ERR_AMBIGUOUS_NAME?     "2":
-                     gpg_err_code (rc) == GPG_ERR_WRONG_KEY_USAGE?    "3":
-                     gpg_err_code (rc) == GPG_ERR_CERT_REVOKED?       "4":
-                     gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED?       "5":
-                     gpg_err_code (rc) == GPG_ERR_NO_CRL_KNOWN?       "6":
-                     gpg_err_code (rc) == GPG_ERR_CRL_TOO_OLD?        "7":
-                     gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH?    "8":
-                     "0",
-                     name, NULL);
+      if (recp_required)
+        {
+          log_error ("can't encrypt to '%s': %s\n", name, gpg_strerror (rc));
+          gpgsm_status2 (ctrl, STATUS_INV_RECP,
+                         get_inv_recpsgnr_code (rc), name, NULL);
+        }
+      else
+        log_info (_("Note: won't be able to encrypt to '%s': %s\n"),
+                  name, gpg_strerror (rc));
     }
 }
 
 
+static void
+parse_validation_model (const char *model)
+{
+  int i = gpgsm_parse_validation_model (model);
+  if (i == -1)
+    log_error (_("unknown validation model '%s'\n"), model);
+  else
+    default_validation_model = i;
+}
+
+
+/* Release the list of SERVERS.  As usual it is okay to call this
+   function with SERVERS passed as NULL.  */
+void
+keyserver_list_free (struct keyserver_spec *servers)
+{
+  while (servers)
+    {
+      struct keyserver_spec *tmp = servers->next;
+      xfree (servers->host);
+      xfree (servers->user);
+      if (servers->pass)
+        memset (servers->pass, 0, strlen (servers->pass));
+      xfree (servers->pass);
+      xfree (servers->base);
+      xfree (servers);
+      servers = tmp;
+    }
+}
+
+/* See also dirmngr ldapserver_parse_one().  */
+struct keyserver_spec *
+parse_keyserver_line (char *line,
+                     const char *filename, unsigned int lineno)
+{
+  char *p;
+  char *endp;
+  struct keyserver_spec *server;
+  int fieldno;
+  int fail = 0;
+
+  /* Parse the colon separated fields.  */
+  server = xcalloc (1, sizeof *server);
+  for (fieldno = 1, p = line; p; p = endp, fieldno++ )
+    {
+      endp = strchr (p, ':');
+      if (endp)
+       *endp++ = '\0';
+      trim_spaces (p);
+      switch (fieldno)
+       {
+       case 1:
+         if (*p)
+           server->host = xstrdup (p);
+         else
+           {
+             log_error (_("%s:%u: no hostname given\n"),
+                        filename, lineno);
+             fail = 1;
+           }
+         break;
+
+       case 2:
+         if (*p)
+           server->port = atoi (p);
+         break;
+
+       case 3:
+         if (*p)
+           server->user = xstrdup (p);
+         break;
+
+       case 4:
+         if (*p && !server->user)
+           {
+             log_error (_("%s:%u: password given without user\n"),
+                        filename, lineno);
+             fail = 1;
+           }
+         else if (*p)
+           server->pass = xstrdup (p);
+         break;
+
+       case 5:
+         if (*p)
+           server->base = xstrdup (p);
+         break;
+
+       default:
+         /* (We silently ignore extra fields.) */
+         break;
+       }
+    }
+
+  if (fail)
+    {
+      log_info (_("%s:%u: skipping this line\n"), filename, lineno);
+      keyserver_list_free (server);
+    }
+
+  return server;
+}
+
+
 int
 main ( int argc, char **argv)
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
   char **orig_argv;
-  const char *fname;
   /*  char *username;*/
   int may_coredump;
   strlist_t sl, remusr= NULL, locusr=NULL;
@@ -721,39 +887,47 @@ main ( int argc, char **argv)
   int default_config =1;
   int default_keyring = 1;
   char *logfile = NULL;
+  char *auditlog = NULL;
+  char *htmlauditlog = NULL;
   int greeting = 0;
   int nogreeting = 0;
   int debug_wait = 0;
   int use_random_seed = 1;
+  int no_common_certs_import = 0;
   int with_fpr = 0;
-  char *def_digest_string = NULL;
+  const char *forced_digest_algo = NULL;
+  const char *extra_digest_algo = NULL;
   enum cmd_and_opt_values cmd = 0;
   struct server_control_s ctrl;
   certlist_t recplist = NULL;
   certlist_t signerlist = NULL;
   int do_not_setup_keys = 0;
+  int recp_required = 0;
+  estream_t auditfp = NULL;
+  estream_t htmlauditfp = NULL;
+  struct assuan_malloc_hooks malloc_hooks;
 
   /*mtrace();*/
 
+  gnupg_reopen_std (GPGSM_NAME);
   /* trap_unaligned ();*/
+  gnupg_rl_initialize ();
   set_strusage (my_strusage);
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
-  /* We don't need any locking in libgcrypt unless we use any kind of
-     threading. */
-  gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING);
 
   /* 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 */
-  log_set_prefix ("gpgsm", 1);
+  log_set_prefix (GPGSM_NAME, 1);
 
   /* Make sure that our subsystems are ready.  */
-  init_common_subsystems ();
+  i18n_init ();
+  init_common_subsystems (&argc, &argv);
 
   /* Check that the libraries are suitable.  Do it here because the
      option parse may need services of the library */
   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
-    log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt", 
+    log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
                NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
   if (!ksba_check_version (NEED_KSBA_VERSION) )
     log_fatal (_("%s is too old (need %s, have %s)\n"), "libksba",
@@ -763,18 +937,23 @@ main ( int argc, char **argv)
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
 
   may_coredump = disable_core_dumps ();
-  
+
   gnupg_init_signals (0, emergency_cleanup);
-  
-  create_dotlock (NULL); /* register locking cleanup */
-  i18n_init();
 
-  opt.def_cipher_algoid = "3DES";  /*des-EDE3-CBC*/
+  dotlock_create (NULL, 0); /* Register lockfile cleanup.  */
+
+  opt.autostart = 1;
+  opt.session_env = session_env_new ();
+  if (!opt.session_env)
+    log_fatal ("error allocating session environment block: %s\n",
+               strerror (errno));
+
+  /* Note: If you change this default cipher algorithm , please
+     remember to update the Gpgconflist entry as well.  */
+  opt.def_cipher_algoid = DEFAULT_CIPHER_ALGO;
 
   opt.homedir = default_homedir ();
-#ifdef HAVE_W32_SYSTEM
-  opt.no_crl_check = 1;
-#endif
+
 
   /* First check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -793,29 +972,34 @@ main ( int argc, char **argv)
           default_config = 0;
        }
       else if (pargs.r_opt == oNoOptions)
-        default_config = 0; /* --no-options */
+        {
+          default_config = 0; /* --no-options */
+          opt.no_homedir_creation = 1;
+        }
       else if (pargs.r_opt == oHomedir)
         opt.homedir = pargs.r.ret_str;
       else if (pargs.r_opt == aCallProtectTool)
         break; /* This break makes sure that --version and --help are
                   passed to the protect-tool. */
     }
-  
-  
-  /* initialize the secure memory. */
+
+
+  /* Initialize the secure memory. */
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
   maybe_setuid = 0;
 
-  /* 
-     Now we are now working under our real uid 
+  /*
+     Now we are now working under our real uid
   */
 
   ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
 
-  assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
-  assuan_set_assuan_log_stream (log_get_stream ());
-  assuan_set_assuan_log_prefix (log_get_prefix (NULL));
-  assuan_set_assuan_err_source (GPG_ERR_SOURCE_DEFAULT);
+  malloc_hooks.malloc = gcry_malloc;
+  malloc_hooks.realloc = gcry_realloc;
+  malloc_hooks.free = gcry_free;
+  assuan_set_malloc_hooks (&malloc_hooks);
+  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+  setup_libassuan_logging (&opt.debug);
 
   keybox_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
 
@@ -823,15 +1007,15 @@ main ( int argc, char **argv)
   memset (&ctrl, 0, sizeof ctrl);
   gpgsm_init_default_ctrl (&ctrl);
   ctrl.no_server = 1;
-  ctrl.status_fd = -1; /* not status output */
+  ctrl.status_fd = -1; /* No status output. */
   ctrl.autodetect_encoding = 1;
 
   /* Set the default option file */
   if (default_config )
-    configname = make_filename (opt.homedir, "gpgsm.conf", NULL);
+    configname = make_filename (opt.homedir, GPGSM_NAME EXTSEP_S "conf", NULL);
   /* Set the default policy file */
   opt.policy_file = make_filename (opt.homedir, "policies.txt", NULL);
-  
+
   argc        = orig_argc;
   argv        = orig_argv;
   pargs.argc  = &argc;
@@ -847,34 +1031,34 @@ main ( int argc, char **argv)
         if (default_config)
           {
             if (parse_debug)
-              log_info (_("NOTE: no default option file `%s'\n"), configname);
+              log_info (_("Note: no default option file '%s'\n"), configname);
           }
-        else 
+        else
           {
-            log_error (_("option file `%s': %s\n"), configname, strerror(errno));
+            log_error (_("option file '%s': %s\n"), configname, strerror(errno));
             gpgsm_exit(2);
           }
         xfree(configname);
         configname = NULL;
       }
     if (parse_debug && configname)
-      log_info (_("reading options from `%s'\n"), configname);
+      log_info (_("reading options from '%s'\n"), configname);
     default_config = 0;
   }
 
-  while (!no_more_options 
+  while (!no_more_options
          && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
     {
       switch (pargs.r_opt)
         {
-       case aGPGConfList: 
-       case aGPGConfTest: 
+       case aGPGConfList:
+       case aGPGConfTest:
           set_cmd (&cmd, pargs.r_opt);
           do_not_setup_keys = 1;
           nogreeting = 1;
           break;
 
-        case aServer: 
+        case aServer:
           opt.batch = 1;
           set_cmd (&cmd, aServer);
           break;
@@ -891,7 +1075,7 @@ main ( int argc, char **argv)
           no_more_options = 1; /* Stop parsing. */
           do_not_setup_keys = 1;
           break;
-        
+
         case aDeleteKey:
           set_cmd (&cmd, aDeleteKey);
           /*greeting=1;*/
@@ -900,42 +1084,47 @@ main ( int argc, char **argv)
 
         case aDetachedSign:
           detached_sig = 1;
-          set_cmd (&cmd, aSign ); 
+          set_cmd (&cmd, aSign );
           break;
 
         case aKeygen:
           set_cmd (&cmd, aKeygen);
-          greeting=1; 
+          greeting=1;
           do_not_setup_keys = 1;
           break;
 
-        case aCheckKeys:
-        case aImport: 
-        case aSendKeys: 
-        case aRecvKeys: 
-        case aExport: 
-        case aExportSecretKeyP12: 
+        case aImport:
+        case aSendKeys:
+        case aRecvKeys:
+        case aExport:
+        case aExportSecretKeyP12:
+        case aExportSecretKeyP8:
+        case aExportSecretKeyRaw:
         case aDumpKeys:
         case aDumpChain:
-        case aDumpExternalKeys: 
-        case aDumpSecretKeys: 
+        case aDumpExternalKeys:
+        case aDumpSecretKeys:
         case aListKeys:
-        case aListExternalKeys: 
-        case aListSecretKeys: 
-        case aListChain: 
-        case aLearnCard: 
-        case aPasswd: 
+        case aListExternalKeys:
+        case aListSecretKeys:
+        case aListChain:
+        case aLearnCard:
+        case aPasswd:
         case aKeydbClearSomeCertFlags:
           do_not_setup_keys = 1;
           set_cmd (&cmd, pargs.r_opt);
           break;
 
+        case aEncr:
+          recp_required = 1;
+          set_cmd (&cmd, pargs.r_opt);
+          break;
+
         case aSym:
-        case aDecrypt: 
-        case aEncr: 
-        case aSign: 
-        case aClearsign: 
-        case aVerify: 
+        case aDecrypt:
+        case aSign:
+        case aClearsign:
+        case aVerify:
           set_cmd (&cmd, pargs.r_opt);
           break;
 
@@ -943,15 +1132,15 @@ main ( int argc, char **argv)
         case oArmor:
           ctrl.create_pem = 1;
           break;
-        case oBase64: 
+        case oBase64:
           ctrl.create_pem = 0;
           ctrl.create_base64 = 1;
           break;
-        case oNoArmor: 
+        case oNoArmor:
           ctrl.create_pem = 0;
           ctrl.create_base64 = 0;
           break;
-          
+
         case oP12Charset:
           opt.p12_charset = pargs.r.ret_str;
           break;
@@ -996,8 +1185,8 @@ main ( int argc, char **argv)
           ctrl.use_ocsp = opt.enable_ocsp = 1;
           break;
 
-        case oIncludeCerts: 
-          ctrl.include_certs = default_include_certs = pargs.r.ret_int; 
+        case oIncludeCerts:
+          ctrl.include_certs = default_include_certs = pargs.r.ret_int;
           break;
 
         case oPolicyFile:
@@ -1014,14 +1203,14 @@ main ( int argc, char **argv)
         case oEnablePolicyChecks:
           opt.no_policy_check = 0;
           break;
-          
+
         case oAutoIssuerKeyRetrieve:
           opt.auto_issuer_key_retrieve = 1;
           break;
 
         case oOutput: opt.outfile = pargs.r.ret_str; break;
 
-        
+
         case oQuiet: opt.quiet = 1; break;
         case oNoTTY: /* fixme:tty_no_terminal(1);*/ break;
         case oDryRun: opt.dry_run = 1; break;
@@ -1036,14 +1225,17 @@ main ( int argc, char **argv)
           break;
 
         case oLogFile: logfile = pargs.r.ret_str; break;
-        case oNoLogFile: logfile = NULL; break;          
+        case oNoLogFile: logfile = NULL; break;
+
+        case oAuditLog: auditlog = pargs.r.ret_str; break;
+        case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break;
 
-        case oBatch: 
+        case oBatch:
           opt.batch = 1;
           greeting = 0;
           break;
         case oNoBatch: opt.batch = 0; break;
-          
+
         case oAnswerYes: opt.answer_yes = 1; break;
         case oAnswerNo: opt.answer_no = 1; break;
 
@@ -1067,10 +1259,14 @@ main ( int argc, char **argv)
           opt.with_md5_fingerprint=1; /*fall thru*/
         case oWithFingerprint:
           with_fpr=1; /*fall thru*/
-        case oFingerprint:
+        case aFingerprint:
           opt.fingerprint++;
           break;
 
+        case oWithKeygrip:
+          opt.with_keygrip = 1;
+          break;
+
         case oOptions:
           /* config files may not be nested (silently ignore them) */
           if (!configfp)
@@ -1080,30 +1276,51 @@ main ( int argc, char **argv)
               goto next_pass;
            }
           break;
-        case oNoOptions: break; /* no-options */
+        case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
         case oHomedir: opt.homedir = pargs.r.ret_str; break;
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
-        case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break;
-        case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break;
-        case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
+
+        case oDisplay:
+          set_opt_session_env ("DISPLAY", pargs.r.ret_str);
+          break;
+        case oTTYname:
+          set_opt_session_env ("GPG_TTY", pargs.r.ret_str);
+          break;
+        case oTTYtype:
+          set_opt_session_env ("TERM", pargs.r.ret_str);
+          break;
+        case oXauthority:
+          set_opt_session_env ("XAUTHORITY", pargs.r.ret_str);
+          break;
+
         case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
         case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break;
+
         case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str;  break;
-        case oPreferSystemDirmngr: opt.prefer_system_dirmngr = 1; break;
+        case oDisableDirmngr: opt.disable_dirmngr = 1;  break;
+        case oPreferSystemDirmngr: /* Obsolete */; break;
         case oProtectToolProgram:
-          opt.protect_tool_program = pargs.r.ret_str; 
+          opt.protect_tool_program = pargs.r.ret_str;
           break;
-          
+
         case oFakedSystemTime:
-          gnupg_set_time ( (time_t)pargs.r.ret_ulong, 0);
+          {
+            time_t faked_time = isotime2epoch (pargs.r.ret_str);
+            if (faked_time == (time_t)(-1))
+              faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
+            gnupg_set_time (faked_time, 0);
+          }
           break;
 
         case oNoDefKeyring: default_keyring = 0; break;
         case oNoGreeting: nogreeting = 1; break;
 
         case oDefaultKey:
-          /* fixme:opt.def_secret_key = pargs.r.ret_str;*/
-          log_info ("WARNING: --default-key has not yet been implemented\n");
+          if (*pargs.r.ret_str)
+            {
+              xfree (opt.local_user);
+              opt.local_user = xstrdup (pargs.r.ret_str);
+            }
           break;
         case oDefRecipient:
           if (*pargs.r.ret_str)
@@ -1122,8 +1339,9 @@ main ( int argc, char **argv)
 
         case oWithKeyData: opt.with_key_data=1; /* fall thru */
         case oWithColons: ctrl.with_colons = 1; break;
+        case oWithSecret: ctrl.with_secret = 1; break;
         case oWithValidation: ctrl.with_validation=1; break;
-        case oWithEphemeralKeys: opt.with_ephemeral_keys=1; break;
+        case oWithEphemeralKeys: ctrl.with_ephemeral_keys=1; break;
 
         case oSkipVerify: opt.skip_verify=1; break;
 
@@ -1137,46 +1355,75 @@ main ( int argc, char **argv)
           add_to_strlist ( &remusr, pargs.r.ret_str);
           break;
 
-        case oTextmodeShort: /*fixme:opt.textmode = 2;*/ break;
-        case oTextmode: /*fixme:opt.textmode=1;*/  break;
-
-        case oUser: /* store the local users, the first one is the default */
+        case oUser: /* Store the local users, the first one is the default */
           if (!opt.local_user)
-            opt.local_user = pargs.r.ret_str;
+            opt.local_user = xstrdup (pargs.r.ret_str);
           add_to_strlist (&locusr, pargs.r.ret_str);
           break;
 
         case oNoSecmemWarn:
-          gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); 
+          gcry_control (GCRYCTL_DISABLE_SECMEM_WARN);
           break;
 
         case oCipherAlgo:
           opt.def_cipher_algoid = pargs.r.ret_str;
           break;
 
-        case oDisableCipherAlgo: 
+        case oDisableCipherAlgo:
           {
             int algo = gcry_cipher_map_name (pargs.r.ret_str);
             gcry_cipher_ctl (NULL, GCRYCTL_DISABLE_ALGO, &algo, sizeof algo);
           }
           break;
-        case oDisablePubkeyAlgo: 
+        case oDisablePubkeyAlgo:
           {
             int algo = gcry_pk_map_name (pargs.r.ret_str);
             gcry_pk_ctl (GCRYCTL_DISABLE_ALGO,&algo, sizeof algo );
           }
           break;
 
+        case oDigestAlgo:
+          forced_digest_algo = pargs.r.ret_str;
+          break;
+
+        case oExtraDigestAlgo:
+          extra_digest_algo = pargs.r.ret_str;
+          break;
+
         case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
         case oNoRandomSeedFile: use_random_seed = 0; break;
+        case oNoCommonCertsImport: no_common_certs_import = 1; break;
 
         case oEnableSpecialFilenames: allow_special_filenames =1; break;
-          
 
-        case aDummy:
+        case oValidationModel: parse_validation_model (pargs.r.ret_str); break;
+
+       case oKeyServer:
+         {
+           struct keyserver_spec *keyserver;
+           keyserver = parse_keyserver_line (pargs.r.ret_str,
+                                             configname, configlineno);
+           if (! keyserver)
+             log_error (_("could not parse keyserver\n"));
+           else
+             {
+               /* FIXME: Keep last next pointer.  */
+               struct keyserver_spec **next_p = &opt.keyserver;
+               while (*next_p)
+                 next_p = &(*next_p)->next;
+               *next_p = keyserver;
+             }
+         }
+         break;
+
+        case oIgnoreCertExtension:
+          add_to_strlist (&opt.ignored_cert_extensions, pargs.r.ret_str);
           break;
-        default: 
-          pargs.err = configfp? 1:2; 
+
+        case oNoAutostart: opt.autostart = 0; break;
+
+        default:
+          pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
           break;
        }
     }
@@ -1194,19 +1441,25 @@ main ( int argc, char **argv)
   configname = NULL;
 
   if (!opt.config_filename)
-    opt.config_filename = make_filename (opt.homedir, "gpgsm.conf", NULL);
+    opt.config_filename = make_filename (opt.homedir,
+                                         GPGSM_NAME EXTSEP_S "conf",
+                                         NULL);
 
   if (log_get_errorcount(0))
     gpgsm_exit(2);
-  
+
+  /* Now that we have the options parsed we need to update the default
+     control structure.  */
+  gpgsm_init_default_ctrl (&ctrl);
+
   if (nogreeting)
     greeting = 0;
-  
+
   if (greeting)
     {
-      fprintf(stderr, "%s %s; %s\n",
-              strusage(11), strusage(13), strusage(14) );
-      fprintf(stderr, "%s\n", strusage(15) );
+      es_fprintf (es_stderr, "%s %s; %s\n",
+                  strusage(11), strusage(13), strusage(14) );
+      es_fprintf (es_stderr, "%s\n", strusage(15) );
     }
 #  ifdef IS_DEVELOPMENT_VERSION
   if (!opt.batch)
@@ -1237,10 +1490,20 @@ main ( int argc, char **argv)
 
       log_info (_("WARNING: running with faked system time: "));
       gnupg_get_isotime (tbuf);
-      gpgsm_dump_time (tbuf);
+      dump_isotime (tbuf);
       log_printf ("\n");
     }
-  
+
+  /* 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]);
+    }
+
 /*FIXME    if (opt.batch) */
 /*      tty_batchmode (1); */
 
@@ -1269,6 +1532,22 @@ main ( int argc, char **argv)
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.2";
   else if (!strcmp (opt.def_cipher_algoid, "AES256") )
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.42";
+  else if (!strcmp (opt.def_cipher_algoid, "SERPENT")
+           || !strcmp (opt.def_cipher_algoid, "SERPENT128") )
+    opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.2";
+  else if (!strcmp (opt.def_cipher_algoid, "SERPENT192") )
+    opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.22";
+  else if (!strcmp (opt.def_cipher_algoid, "SERPENT192") )
+    opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.42";
+  else if (!strcmp (opt.def_cipher_algoid, "SEED") )
+    opt.def_cipher_algoid = "1.2.410.200004.1.4";
+  else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA")
+           || !strcmp (opt.def_cipher_algoid, "CAMELLIA128") )
+    opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.2";
+  else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA192") )
+    opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.3";
+  else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA256") )
+    opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.4";
 
   if (cmd != aGPGConfList)
     {
@@ -1276,45 +1555,50 @@ main ( int argc, char **argv)
            || !gcry_cipher_mode_from_oid (opt.def_cipher_algoid))
         log_error (_("selected cipher algorithm is invalid\n"));
 
-      if (def_digest_string)
+      if (forced_digest_algo)
         {
-          opt.def_digest_algo = gcry_md_map_name (def_digest_string);
-          xfree (def_digest_string);
-          def_digest_string = NULL;
-          if (our_md_test_algo(opt.def_digest_algo) )
+          opt.forced_digest_algo = gcry_md_map_name (forced_digest_algo);
+          if (our_md_test_algo(opt.forced_digest_algo) )
+            log_error (_("selected digest algorithm is invalid\n"));
+        }
+      if (extra_digest_algo)
+        {
+          opt.extra_digest_algo = gcry_md_map_name (extra_digest_algo);
+          if (our_md_test_algo (opt.extra_digest_algo) )
             log_error (_("selected digest algorithm is invalid\n"));
         }
     }
 
   if (log_get_errorcount(0))
     gpgsm_exit(2);
-  
-  /* Set the random seed file. */
-  if (use_random_seed) {
-    char *p = make_filename (opt.homedir, "random_seed", NULL);
-    gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
-    xfree(p);
-  }
 
+  /* Set the random seed file. */
+  if (use_random_seed)
+    {
+      char *p = make_filename (opt.homedir, "random_seed", NULL);
+      gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
+      xfree(p);
+    }
 
   if (!cmd && opt.fingerprint && !with_fpr)
     set_cmd (&cmd, aListKeys);
-  
-  if (!nrings && default_keyring)  /* Add default keybox. */
+
+  /* Add default keybox. */
+  if (!nrings && default_keyring)
     {
       int created;
 
       keydb_add_resource ("pubring.kbx", 0, 0, &created);
-      if (created)
+      if (created && !no_common_certs_import)
         {
           /* Import the standard certificates for a new default keybox. */
           char *filelist[2];
-          
+
           filelist[0] = make_filename (gnupg_datadir (),"com-certs.pem", NULL);
           filelist[1] = NULL;
           if (!access (filelist[0], F_OK))
             {
-              log_info (_("importing common certificates `%s'\n"),
+              log_info (_("importing common certificates '%s'\n"),
                         filelist[0]);
               gpgsm_import_files (&ctrl, 1, filelist, open_read);
             }
@@ -1325,6 +1609,29 @@ main ( int argc, char **argv)
     keydb_add_resource (sl->d, 0, 0, NULL);
   FREE_STRLIST(nrings);
 
+
+  /* Prepare the audit log feature for certain commands.  */
+  if (auditlog || htmlauditlog)
+    {
+      switch (cmd)
+        {
+        case aEncr:
+        case aSign:
+        case aDecrypt:
+        case aVerify:
+          audit_release (ctrl.audit);
+          ctrl.audit = audit_new ();
+          if (auditlog)
+            auditfp = open_es_fwrite (auditlog);
+          if (htmlauditlog)
+            htmlauditfp = open_es_fwrite (htmlauditlog);
+          break;
+        default:
+          break;
+        }
+    }
+
+
   if (!do_not_setup_keys)
     {
       for (sl = locusr; sl ; sl = sl->next)
@@ -1332,99 +1639,69 @@ main ( int argc, char **argv)
           int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 1, &signerlist, 0);
           if (rc)
             {
-              log_error (_("can't sign using `%s': %s\n"),
+              log_error (_("can't sign using '%s': %s\n"),
                          sl->d, gpg_strerror (rc));
+              gpgsm_status2 (&ctrl, STATUS_INV_SGNR,
+                             get_inv_recpsgnr_code (rc), sl->d, NULL);
               gpgsm_status2 (&ctrl, STATUS_INV_RECP,
-                         gpg_err_code (rc) == -1?                      "1":
-                         gpg_err_code (rc) == GPG_ERR_NO_PUBKEY?       "1":
-                         gpg_err_code (rc) == GPG_ERR_AMBIGUOUS_NAME?  "2":
-                         gpg_err_code (rc) == GPG_ERR_WRONG_KEY_USAGE? "3":
-                         gpg_err_code (rc) == GPG_ERR_CERT_REVOKED?    "4":
-                         gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED?    "5":
-                         gpg_err_code (rc) == GPG_ERR_NO_CRL_KNOWN?    "6":
-                         gpg_err_code (rc) == GPG_ERR_CRL_TOO_OLD?     "7":
-                         gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH? "8":
-                         gpg_err_code (rc) == GPG_ERR_NO_SECKEY?       "9":
-                         "0",
-                         sl->d, NULL);
+                             get_inv_recpsgnr_code (rc), sl->d, NULL);
             }
         }
-      
+
       /* Build the recipient list.  We first add the regular ones and then
-         the encrypt-to ones because the underlying function will silenty
+         the encrypt-to ones because the underlying function will silently
          ignore duplicates and we can't allow to keep a duplicate which is
          flagged as encrypt-to as the actually encrypt function would then
          complain about no (regular) recipients. */
       for (sl = remusr; sl; sl = sl->next)
         if (!(sl->flags & 1))
-          do_add_recipient (&ctrl, sl->d, &recplist, 0);
+          do_add_recipient (&ctrl, sl->d, &recplist, 0, recp_required);
       if (!opt.no_encrypt_to)
         {
           for (sl = remusr; sl; sl = sl->next)
             if ((sl->flags & 1))
-              do_add_recipient (&ctrl, sl->d, &recplist, 1);
+              do_add_recipient (&ctrl, sl->d, &recplist, 1, recp_required);
         }
     }
 
   if (log_get_errorcount(0))
-    gpgsm_exit(1); /* must stop for invalid recipients */
-  
-  fname = argc? *argv : NULL;
-  
+    gpgsm_exit(1); /* Must stop for invalid recipients. */
+
+  /* Dispatch command.  */
   switch (cmd)
     {
-    case aGPGConfList: 
+    case aGPGConfList:
       { /* List options and default values in the GPG Conf format.  */
-
-        /* The following list is taken from gnupg/tools/gpgconf-comp.c.  */
-        /* Option flags.  YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
-           FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE.  */
-#define GC_OPT_FLAG_NONE       0UL
-        /* The RUNTIME flag for an option indicates that the option can be
-           changed at runtime.  */
-#define GC_OPT_FLAG_RUNTIME    (1UL << 3)
-        /* The DEFAULT flag for an option indicates that the option has a
-           default value.  */
-#define GC_OPT_FLAG_DEFAULT    (1UL << 4)
-        /* The DEF_DESC flag for an option indicates that the option has a
-           default, which is described by the value of the default field.  */
-#define GC_OPT_FLAG_DEF_DESC   (1UL << 5)
-        /* The NO_ARG_DESC flag for an option indicates that the argument has
-           a default, which is described by the value of the ARGDEF field.  */
-#define GC_OPT_FLAG_NO_ARG_DESC        (1UL << 6)
-
        char *config_filename_esc = percent_escape (opt.config_filename, NULL);
 
-        printf ("gpgconf-gpgsm.conf:%lu:\"%s\n",
-                GC_OPT_FLAG_DEFAULT, config_filename_esc);
+        es_printf ("%s-%s.conf:%lu:\"%s\n",
+                   GPGCONF_NAME, GPGSM_NAME,
+                   GC_OPT_FLAG_DEFAULT, config_filename_esc);
         xfree (config_filename_esc);
 
-        printf ("verbose:%lu:\n"
-                "quiet:%lu:\n"
-                "debug-level:%lu:\"none:\n"
-                "log-file:%lu:\n",
-                GC_OPT_FLAG_NONE,
-                GC_OPT_FLAG_NONE,
-                GC_OPT_FLAG_DEFAULT,
-                GC_OPT_FLAG_NONE );
-        printf ("disable-crl-checks:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("disable-trusted-cert-crl-check:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("enable-ocsp:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("include-certs:%lu:1:\n",
-                GC_OPT_FLAG_DEFAULT );
-        printf ("disable-policy-checks:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("auto-issuer-key-retrieve:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("prefer-system-dirmngr:%lu:\n",
-                GC_OPT_FLAG_NONE );
-        printf ("cipher-algo:%lu:\"3DES:\n",
-                GC_OPT_FLAG_DEFAULT );
-        printf ("p12-charset:%lu:\n",
-                GC_OPT_FLAG_DEFAULT );
+        es_printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE);
+       es_printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE);
+       es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
+       es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("disable-crl-checks:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("disable-trusted-cert-crl-check:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("enable-ocsp:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("include-certs:%lu:%d:\n", GC_OPT_FLAG_DEFAULT,
+                   DEFAULT_INCLUDE_CERTS);
+        es_printf ("disable-policy-checks:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("auto-issuer-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
+        es_printf ("cipher-algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
+                   DEFAULT_CIPHER_ALGO);
+        es_printf ("p12-charset:%lu:\n", GC_OPT_FLAG_DEFAULT);
+        es_printf ("default-key:%lu:\n", GC_OPT_FLAG_DEFAULT);
+        es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_DEFAULT);
+       es_printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE);
+
+        /* The next one is an info only item and should match what
+           proc_parameters actually implements.  */
+        es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
+                   "RSA-2048");
 
       }
       break;
@@ -1458,42 +1735,40 @@ main ( int argc, char **argv)
 
     case aEncr: /* Encrypt the given file. */
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         set_binary (stdin);
 
         if (!argc) /* Source is stdin. */
-          gpgsm_encrypt (&ctrl, recplist, 0, fp); 
+          gpgsm_encrypt (&ctrl, recplist, 0, fp);
         else if (argc == 1)  /* Source is the given file. */
           gpgsm_encrypt (&ctrl, recplist, open_read (*argv), fp);
         else
           wrong_args ("--encrypt [datafile]");
 
-        if (fp != stdout)
-          fclose (fp);
+        es_fclose (fp);
       }
       break;
 
     case aSign: /* Sign the given file. */
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         /* Fixme: We should also allow to concatenate multiple files for
            signing because that is what gpg does.*/
         set_binary (stdin);
         if (!argc) /* Create from stdin. */
-          gpgsm_sign (&ctrl, signerlist, 0, detached_sig, fp); 
+          gpgsm_sign (&ctrl, signerlist, 0, detached_sig, fp);
         else if (argc == 1) /* From file. */
           gpgsm_sign (&ctrl, signerlist,
-                      open_read (*argv), detached_sig, fp); 
+                      open_read (*argv), detached_sig, fp);
         else
           wrong_args ("--sign [datafile]");
 
-        if (fp != stdout)
-          fclose (fp);
+        es_fclose (fp);
       }
       break;
-        
+
     case aSignEncr: /* sign and encrypt the given file */
       log_error ("this command has not yet been implemented\n");
       break;
@@ -1504,35 +1779,30 @@ main ( int argc, char **argv)
 
     case aVerify:
       {
-        FILE *fp = NULL;
+        estream_t fp = NULL;
 
         set_binary (stdin);
         if (argc == 2 && opt.outfile)
           log_info ("option --output ignored for a detached signature\n");
         else if (opt.outfile)
-          fp = open_fwrite (opt.outfile);
+          fp = open_es_fwrite (opt.outfile);
 
         if (!argc)
           gpgsm_verify (&ctrl, 0, -1, fp); /* normal signature from stdin */
         else if (argc == 1)
           gpgsm_verify (&ctrl, open_read (*argv), -1, fp); /* std signature */
         else if (argc == 2) /* detached signature (sig, detached) */
-          gpgsm_verify (&ctrl, open_read (*argv), open_read (argv[1]), NULL); 
+          gpgsm_verify (&ctrl, open_read (*argv), open_read (argv[1]), NULL);
         else
           wrong_args ("--verify [signature [detached_data]]");
 
-        if (fp && fp != stdout)
-          fclose (fp);
+        es_fclose (fp);
       }
       break;
 
-    case aVerifyFiles:
-      log_error (_("this command has not yet been implemented\n"));
-      break;
-
     case aDecrypt:
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         set_binary (stdin);
         if (!argc)
@@ -1541,8 +1811,8 @@ main ( int argc, char **argv)
           gpgsm_decrypt (&ctrl, open_read (*argv), fp); /* from file */
         else
           wrong_args ("--decrypt [filename]");
-        if (fp != stdout)
-          fclose (fp);
+
+        es_fclose (fp);
       }
       break;
 
@@ -1570,7 +1840,7 @@ main ( int argc, char **argv)
           {
           case aListChain:
           case aListKeys:         mode = (0   | 0 | (1<<6)); break;
-          case aDumpChain: 
+          case aDumpChain:
           case aDumpKeys:         mode = (256 | 0 | (1<<6)); break;
           case aListExternalKeys: mode = (0   | 0 | (1<<7)); break;
           case aDumpExternalKeys: mode = (256 | 0 | (1<<7)); break;
@@ -1591,10 +1861,27 @@ main ( int argc, char **argv)
 
     case aKeygen: /* Generate a key; well kind of. */
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
-        gpgsm_gencertreq_tty (&ctrl, fp);
-        if (fp != stdout)
-          fclose (fp);
+        estream_t fpin = NULL;
+        estream_t fpout;
+
+        if (opt.batch)
+          {
+            if (!argc) /* Create from stdin. */
+              fpin = open_es_fread ("-", "r");
+            else if (argc == 1) /* From file. */
+              fpin = open_es_fread (*argv, "r");
+            else
+              wrong_args ("--gen-key --batch [parmfile]");
+          }
+
+        fpout = open_es_fwrite (opt.outfile?opt.outfile:"-");
+
+        if (fpin)
+          gpgsm_genkey (&ctrl, fpin, fpout);
+        else
+          gpgsm_gencertreq_tty (&ctrl, fpout);
+
+        es_fclose (fpout);
       }
       break;
 
@@ -1605,30 +1892,56 @@ main ( int argc, char **argv)
 
     case aExport:
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        estream_t fp;
 
+        fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
         for (sl=NULL; argc; argc--, argv++)
           add_to_strlist (&sl, *argv);
-        gpgsm_export (&ctrl, sl, fp, NULL);
+        gpgsm_export (&ctrl, sl, fp);
         free_strlist(sl);
-        if (fp != stdout)
-          fclose (fp);
+        es_fclose (fp);
       }
       break;
 
     case aExportSecretKeyP12:
       {
-        FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         if (argc == 1)
-          gpgsm_p12_export (&ctrl, *argv, stdout);
+          gpgsm_p12_export (&ctrl, *argv, fp, 0);
         else
           wrong_args ("--export-secret-key-p12 KEY-ID");
-        if (fp != stdout)
-          fclose (fp);
+        if (fp != es_stdout)
+          es_fclose (fp);
       }
       break;
-      
+
+    case aExportSecretKeyP8:
+      {
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
+
+        if (argc == 1)
+          gpgsm_p12_export (&ctrl, *argv, fp, 1);
+        else
+          wrong_args ("--export-secret-key-p8 KEY-ID");
+        if (fp != es_stdout)
+          es_fclose (fp);
+      }
+      break;
+
+    case aExportSecretKeyRaw:
+      {
+        estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
+
+        if (argc == 1)
+          gpgsm_p12_export (&ctrl, *argv, fp, 2);
+        else
+          wrong_args ("--export-secret-key-raw KEY-ID");
+        if (fp != es_stdout)
+          es_fclose (fp);
+      }
+      break;
+
     case aSendKeys:
     case aRecvKeys:
       log_error ("this command has not yet been implemented\n");
@@ -1660,7 +1973,7 @@ main ( int argc, char **argv)
             ;
           else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
             rc = gpg_error (GPG_ERR_BUG);
-          else 
+          else
             {
               char *desc = gpgsm_format_keydesc (cert);
               rc = gpgsm_agent_passwd (&ctrl, grip, desc);
@@ -1682,11 +1995,26 @@ main ( int argc, char **argv)
 
 
     default:
-        log_error ("invalid command (there is no implicit command)\n");
+        log_error (_("invalid command (there is no implicit command)\n"));
        break;
     }
-  
+
+  /* Print the audit result if needed.  */
+  if ((auditlog && auditfp) || (htmlauditlog && htmlauditfp))
+    {
+      if (auditlog && auditfp)
+        audit_print_result (ctrl.audit, auditfp, 0);
+      if (htmlauditlog && htmlauditfp)
+        audit_print_result (ctrl.audit, htmlauditfp, 1);
+      audit_release (ctrl.audit);
+      ctrl.audit = NULL;
+      es_fclose (auditfp);
+      es_fclose (htmlauditfp);
+    }
+
   /* cleanup */
+  keyserver_list_free (opt.keyserver);
+  opt.keyserver = NULL;
   gpgsm_release_certlist (recplist);
   gpgsm_release_certlist (signerlist);
   FREE_STRLIST (remusr);
@@ -1725,9 +2053,23 @@ gpgsm_init_default_ctrl (struct server_control_s *ctrl)
 {
   ctrl->include_certs = default_include_certs;
   ctrl->use_ocsp = opt.enable_ocsp;
+  ctrl->validation_model = default_validation_model;
 }
 
 
+int
+gpgsm_parse_validation_model (const char *model)
+{
+  if (!ascii_strcasecmp (model, "shell") )
+    return 0;
+  else if ( !ascii_strcasecmp (model, "chain") )
+    return 1;
+  else if ( !ascii_strcasecmp (model, "steed") )
+    return 2;
+  else
+    return -1;
+}
+
 
 /* Check whether the filename has the form "-&nnnn", where n is a
    non-zero number.  Returns this number or -1 if it is not the case.  */
@@ -1737,22 +2079,22 @@ check_special_filename (const char *fname, int for_write)
   if (allow_special_filenames
       && fname && *fname == '-' && fname[1] == '&' ) {
     int i;
-    
+
     fname += 2;
     for (i=0; isdigit (fname[i]); i++ )
       ;
-    if ( !fname[i] ) 
-      return translate_sys2libc_fd (atoi (fname), for_write);
+    if ( !fname[i] )
+      return translate_sys2libc_fd_int (atoi (fname), for_write);
   }
   return -1;
 }
 
 
 
-/* Open the FILENAME for read and return the filedescriptor.  Stop
+/* Open the FILENAME for read and return the file descriptor.  Stop
    with an error message in case of problems.  "-" denotes stdin and
-   if special filenames are allowed the given fd is opened instead. */
-static int 
+   if special filenames are allowed the given fd is opened instead.  */
+static int
 open_read (const char *filename)
 {
   int fd;
@@ -1768,44 +2110,37 @@ open_read (const char *filename)
   fd = open (filename, O_RDONLY | O_BINARY);
   if (fd == -1)
     {
-      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
+      log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fd;
 }
 
-/* Open FILENAME for fwrite and return the stream.  Stop with an error
-   message in case of problems.  "-" denotes stdout and if special
-   filenames are allowed the given fd is opened instead. Caller must
-   close the returned stream unless it is stdout. */
-static FILE *
-open_fwrite (const char *filename)
+/* Same as open_read but return an estream_t.  */
+static estream_t
+open_es_fread (const char *filename, const char *mode)
 {
   int fd;
-  FILE *fp;
+  estream_t fp;
 
   if (filename[0] == '-' && !filename[1])
-    {
-      set_binary (stdout);
-      return stdout;
-    }
-
-  fd = check_special_filename (filename, 1);
+    fd = fileno (stdin);
+  else
+    fd = check_special_filename (filename, 0);
   if (fd != -1)
     {
-      fp = fdopen (dup (fd), "wb");
+      fp = es_fdopen_nc (fd, mode);
       if (!fp)
         {
-          log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
+          log_error ("es_fdopen(%d) failed: %s\n", fd, strerror (errno));
           gpgsm_exit (2);
         }
-      set_binary (fp);
       return fp;
     }
-  fp = fopen (filename, "wb");
+  fp = es_fopen (filename, mode);
   if (!fp)
     {
-      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
+      log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fp;
@@ -1843,7 +2178,7 @@ open_es_fwrite (const char *filename)
   fp = es_fopen (filename, "wb");
   if (!fp)
     {
-      log_error (_("can't open `%s': %s\n"), filename, strerror (errno));
+      log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fp;
@@ -1853,7 +2188,10 @@ open_es_fwrite (const char *filename)
 static void
 run_protect_tool (int argc, char **argv)
 {
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
+  (void)argc;
+  (void)argv;
+#else
   const char *pgm;
   char **av;
   int i;
@@ -1870,8 +2208,8 @@ run_protect_tool (int argc, char **argv)
   for (i=1; argc; i++, argc--, argv++)
     av[i] = *argv;
   av[i] = NULL;
-  execv (pgm, av); 
-  log_error ("error executing `%s': %s\n", pgm, strerror (errno));
-#endif /*HAVE_W32_SYSTEM*/
+  execv (pgm, av);
+  log_error ("error executing '%s': %s\n", pgm, strerror (errno));
+#endif /*!HAVE_W32_SYSTEM*/
   gpgsm_exit (2);
 }