See ChangeLog: Tue Dec 29 14:41:47 CET 1998 Werner Koch
[gnupg.git] / g10 / g10.c
index a13abd7..dd8fddb 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -1,14 +1,14 @@
-/* g10.c - The GNUPG utility (main for gpg)
+/* g10.c - The GnuPG utility (main for gpg)
  *     Copyright (C) 1998 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <unistd.h>
 
-/* #define MAINTAINER_OPTIONS */
+#define MAINTAINER_OPTIONS
 
 #include "packet.h"
 #include "iobuf.h"
@@ -41,6 +42,7 @@
 #include "ttyio.h"
 #include "i18n.h"
 #include "status.h"
+#include "g10defs.h"
 
 #ifndef IS_G10MAINT
   #define IS_G10 1
@@ -56,9 +58,10 @@ enum cmd_and_opt_values { aNull = 0,
     oKOption     = 'k',
     oDryRun      = 'n',
     oOutput      = 'o',
+    oQuiet       = 'q',
     oRemote      = 'r',
     aSign        = 's',
-    oTextmode    = 't',
+    oTextmodeShort= 't',
     oUser        = 'u',
     oVerbose     = 'v',
     oCompress    = 'z',
@@ -75,11 +78,13 @@ enum cmd_and_opt_values { aNull = 0,
     aKMode,
     aKModeC,
     aImport,
+    aFastImport,
     aVerify,
     aListKeys,
     aListSigs,
     aListSecretKeys,
     aExport,
+    aExportAll,
     aExportSecret,
     aCheckKeys,
     aGenRevoke,
@@ -87,6 +92,8 @@ enum cmd_and_opt_values { aNull = 0,
     aPrintMD,
     aPrintMDs,
     aCheckTrustDB,
+    aUpdateTrustDB,
+    aFixTrustDB,
     aListTrustDB,
     aListTrustPath,
     aExportOwnerTrust,
@@ -95,13 +102,14 @@ enum cmd_and_opt_values { aNull = 0,
     aEnArmor,
     aGenRandom,
 
+    oTextmode,
     oFingerprint,
-    oDoNotExportRSA,
     oAnswerYes,
     oAnswerNo,
     oKeyring,
     oSecretKeyring,
     oDefaultKey,
+    oTrustedKey,
     oOptions,
     oDebug,
     oDebugAll,
@@ -109,6 +117,7 @@ enum cmd_and_opt_values { aNull = 0,
     oNoComment,
     oCompletesNeeded,
     oMarginalsNeeded,
+    oMaxCertDepth,
     oLoadExtension,
     oRFC1991,
     oCipherAlgo,
@@ -135,6 +144,14 @@ enum cmd_and_opt_values { aNull = 0,
     oSetFilename,
     oComment,
     oThrowKeyid,
+    oForceV3Sigs,
+    oS2KMode,
+    oS2KDigest,
+    oS2KCipher,
+    oCharset,
+    oNotDashEscaped,
+    oEscapeFrom,
+    oLockOnce,
 aTest };
 
 
@@ -165,15 +182,22 @@ static ARGPARSE_OPTS opts[] = {
     { aEditKey, "edit-key"  ,256, N_("sign or edit a key")},
     { aGenRevoke, "gen-revoke",256, N_("generate a revocation certificate")},
   #endif
-    { aExport, "export"          , 256, N_("export keys") },
+    { aExport, "export"           , 256, N_("export keys") },
+    { aExportAll, "export-all"    , 256, "@" },
     { aExportSecret, "export-secret-keys" , 256, "@" },
-    { oDoNotExportRSA, "do-not-export-rsa", 0, "@" },
     { aImport, "import",      256     , N_("import/merge keys")},
+    { aFastImport, "fast-import",  256 , "@"},
     { aListPackets, "list-packets",256,N_("list only the sequence of packets")},
   #ifdef IS_G10MAINT
-    { aExportOwnerTrust, "export-ownertrust", 256, N_("export the ownertrust values")},
-    { aImportOwnerTrust, "import-ownertrust", 256 , N_("import ownertrust values")},
-    { aCheckTrustDB, "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
+    { aExportOwnerTrust,
+             "export-ownertrust", 256, N_("export the ownertrust values")},
+    { aImportOwnerTrust,
+             "import-ownertrust", 256 , N_("import ownertrust values")},
+    { aUpdateTrustDB,
+             "update-trustdb",0 , N_("|[NAMES]|update the trust database")},
+    { aCheckTrustDB,
+             "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
+    { aFixTrustDB, "fix-trustdb",0 , N_("fix a corrupted trust database")},
     { aDeArmor, "dearmor", 256, N_("De-Armor a file or stdin") },
     { aEnArmor, "enarmor", 256, N_("En-Armor a file or stdin") },
     { aPrintMD,  "print-md" , 256, N_("|algo [files]|print message digests")},
@@ -191,10 +215,13 @@ static ARGPARSE_OPTS opts[] = {
     { oUser, "local-user",2, N_("use this user-id to sign or decrypt")},
     { oRemote, "remote-user", 2, N_("use this user-id for encryption")},
     { 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") },
+    { oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") },
  /* { oDryRun, "dry-run",   0, N_("do not make any changes") }, */
     { oBatch, "batch",     0, N_("batch mode: never ask")},
     { oAnswerYes, "yes",       0, N_("assume yes on most questions")},
@@ -202,6 +229,7 @@ static ARGPARSE_OPTS opts[] = {
     { 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")},
+    { oCharset, "charset"   , 2, N_("|NAME|set terminal charset to NAME") },
     { oOptions, "options"   , 2, N_("read options from file")},
 
     { oDebug, "debug"     ,4|16, N_("set debugging flags")},
@@ -210,8 +238,15 @@ static ARGPARSE_OPTS opts[] = {
     { oNoComment, "no-comment", 0,   N_("do not write comment packets")},
     { oCompletesNeeded, "completes-needed", 1, N_("(default is 1)")},
     { oMarginalsNeeded, "marginals-needed", 1, N_("(default is 3)")},
-    { oLoadExtension, "load-extension" ,2, N_("|file|load extension module")},
+    { oMaxCertDepth,   "max-cert-depth", 1, "@" },
+    { oTrustedKey, "trusted-key", 2, N_("|KEYID|ulimately trust this key")},
+    { oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")},
     { oRFC1991, "rfc1991",   0, N_("emulate the mode described in RFC1991")},
+    { oS2KMode, "s2k-mode",  1, N_("|N|use passphrase mode N")},
+    { oS2KDigest, "s2k-digest-algo",2,
+               N_("|NAME|use message digest algorithm NAME for passphrases")},
+    { oS2KCipher, "s2k-cipher-algo",2,
+               N_("|NAME|use cipher algorithm NAME for passphrases")},
   #ifdef IS_G10
     { oCipherAlgo, "cipher-algo", 2 , N_("|NAME|use cipher algorithm NAME")},
     { oDigestAlgo, "digest-algo", 2 , N_("|NAME|use message digest algorithm NAME")},
@@ -226,22 +261,20 @@ static ARGPARSE_OPTS opts[] = {
   #ifdef IS_G10
     { 302, NULL, 0, N_("@\nExamples:\n\n"
     " -se -r Bob [file]          sign and encrypt for user Bob\n"
-    " -sat [file]                make a clear text signature\n"
-    " -sb  [file]                make a detached signature\n"
-    " -k   [userid]              show keys\n"
-    " -kc  [userid]              show fingerprint\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"  ) },
   #endif
 
   /* hidden options */
   #ifdef IS_G10MAINT
-    { aTest, "test"      , 0, "@" },
     { aExportOwnerTrust, "list-ownertrust",0 , "@"},  /* alias */
     { aListTrustDB, "list-trustdb",0 , "@"},
     { aListTrustPath, "list-trust-path",0, "@"},
   #endif
   #ifdef IS_G10
     { oKOption, NULL,   0, "@"},
-    { aEditKey, "edit-sig"  ,0, "@"}, /* alias for edit-key */
     { oPasswdFD, "passphrase-fd",1, "@" },
     { aSignKey, "sign-key"  ,256, "@" }, /* alias for edit-key */
   #endif
@@ -268,10 +301,16 @@ static ARGPARSE_OPTS opts[] = {
     { oRunAsShmCP, "run-as-shm-coprocess", 4, "@" },
     { oSetFilename, "set-filename", 2, "@" },
     { oComment, "comment", 2, "@" },
+    { oNotDashEscaped, "not-dash-escaped", 0, "@" },
+    { oEscapeFrom, "escape-from-lines", 0, "@" },
+    { oLockOnce, "lock-once", 0, "@" },
 {0} };
 
 
 
+int g10_errors_seen = 0;
+
+
 static int maybe_setuid = 1;
 
 static char *build_list( const char *text,
@@ -291,9 +330,9 @@ strusage( int level )
     switch( level ) {
       case 11: p =
          #ifdef IS_G10MAINT
-           "gpgm (GNUPG)";
+           "gpgm (GnuPG)";
          #else
-           "gpg (GNUPG)";
+           "gpg (GnuPG)";
          #endif
        break;
       case 13: p = VERSION; break;
@@ -312,7 +351,7 @@ strusage( int level )
       case 41: p =
          #ifdef IS_G10MAINT
            _("Syntax: gpgm [options] [files]\n"
-             "GNUPG maintenance utility\n");
+             "GnuPG maintenance utility\n");
          #else
            _("Syntax: gpg [options] [files]\n"
              "sign, check, encrypt or decrypt\n"
@@ -381,8 +420,8 @@ i18n_init(void)
 {
   #ifdef ENABLE_NLS
     #ifdef HAVE_LC_MESSAGES
-       setlocale( LC_MESSAGES, "" );
        setlocale( LC_TIME, "" );
+       setlocale( LC_MESSAGES, "" );
     #else
        setlocale( LC_ALL, "" );
     #endif
@@ -465,18 +504,21 @@ main( int argc, char **argv )
     unsigned configlineno;
     int parse_debug = 0;
     int default_config =1;
-    int errors=0;
     int default_keyring = 1;
     int greeting = 1;
     enum cmd_and_opt_values cmd = 0;
     const char *trustdb_name = NULL;
     char *def_cipher_string = NULL;
     char *def_digest_string = NULL;
+    char *s2k_cipher_string = NULL;
+    char *s2k_digest_string = NULL;
+    int pwfd = -1;
   #ifdef USE_SHM_COPROCESSING
     ulong requested_shm_size=0;
   #endif
 
     trap_unaligned();
+    secmem_set_flags( secmem_get_flags() | 2 ); /* suspend warnings */
   #ifdef IS_G10MAINT
     secmem_init( 0 );     /* disable use of secmem */
     maybe_setuid = 0;
@@ -489,16 +531,20 @@ main( int argc, char **argv )
     log_set_name("gpg");
     secure_random_alloc(); /* put random number into secure memory */
     disable_core_dumps();
-    init_signals();
   #endif
+    init_signals();
     i18n_init();
     opt.compress = -1; /* defaults to standard compress level */
     /* fixme: set the next two to zero and decide where used */
     opt.def_cipher_algo = 0;
     opt.def_digest_algo = 0;
     opt.def_compress_algo = 2;
+    opt.s2k_mode = 1; /* salted */
+    opt.s2k_digest_algo = DIGEST_ALGO_RMD160;
+    opt.s2k_cipher_algo = CIPHER_ALGO_BLOWFISH;
     opt.completes_needed = 1;
     opt.marginals_needed = 3;
+    opt.max_cert_depth = 5;
     opt.homedir = getenv("GNUPGHOME");
     if( !opt.homedir || !*opt.homedir ) {
       #ifdef __MINGW32__
@@ -527,8 +573,33 @@ main( int argc, char **argv )
            default_config = 0; /* --no-options */
        else if( pargs.r_opt == oHomedir )
            opt.homedir = pargs.r.ret_str;
+      #ifdef USE_SHM_COPROCESSING
+       else if( pargs.r_opt == oRunAsShmCP ) {
+           /* does not make sense in a options file, we do it here,
+            * so that we are the able to drop setuid as soon as possible */
+           opt.shm_coprocess = 1;
+           requested_shm_size = pargs.r.ret_ulong;
+       }
+      #endif
     }
 
+
+  #ifdef USE_SHM_COPROCESSING
+    if( opt.shm_coprocess ) {
+      #ifdef IS_G10
+       init_shm_coprocessing(requested_shm_size, 1 );
+      #else
+       init_shm_coprocessing(requested_shm_size, 0 );
+      #endif
+    }
+  #endif
+  #ifdef IS_G10
+    /* initialize the secure memory. */
+    secmem_init( 16384 );
+    maybe_setuid = 0;
+    /* Okay, we are now working under our real uid */
+  #endif
+
     if( default_config )
        configname = make_filename(opt.homedir, "options", NULL );
 
@@ -544,18 +615,18 @@ main( int argc, char **argv )
        if( !configfp ) {
            if( default_config ) {
                if( parse_debug )
-                   log_info(_("note: no default option file '%s'\n"),
+                   log_info(_("NOTE: no default option file `%s'\n"),
                                                            configname );
            }
            else {
-               log_error(_("option file '%s': %s\n"),
+               log_error(_("option file `%s': %s\n"),
                                    configname, strerror(errno) );
-               g10_exit(1);
+               g10_exit(2);
            }
            m_free(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;
     }
 
@@ -565,7 +636,9 @@ main( int argc, char **argv )
          case aCheckKeys: set_cmd( &cmd, aCheckKeys); break;
          case aListPackets: set_cmd( &cmd, aListPackets); break;
          case aImport: set_cmd( &cmd, aImport); break;
+         case aFastImport: set_cmd( &cmd, aFastImport); break;
          case aExport: set_cmd( &cmd, aExport); break;
+         case aExportAll: set_cmd( &cmd, aExportAll); break;
          case aListKeys: set_cmd( &cmd, aListKeys); break;
          case aListSigs: set_cmd( &cmd, aListSigs); break;
          case aExportSecret: set_cmd( &cmd, aExportSecret); break;
@@ -588,13 +661,14 @@ main( int argc, char **argv )
        #else
          #ifdef MAINTAINER_OPTIONS
            case aPrimegen: set_cmd( &cmd, aPrimegen); break;
-           case aTest: set_cmd( &cmd, aTest); break;
            case aGenRandom: set_cmd( &cmd, aGenRandom); break;
          #endif
          case aPrintMD: set_cmd( &cmd, aPrintMD); break;
          case aPrintMDs: set_cmd( &cmd, aPrintMDs); break;
          case aListTrustDB: set_cmd( &cmd, aListTrustDB); break;
          case aCheckTrustDB: set_cmd( &cmd, aCheckTrustDB); break;
+         case aUpdateTrustDB: set_cmd( &cmd, aUpdateTrustDB); break;
+         case aFixTrustDB: set_cmd( &cmd, aFixTrustDB); break;
          case aListTrustPath: set_cmd( &cmd, aListTrustPath); break;
          case aDeArmor: set_cmd( &cmd, aDeArmor); break;
          case aEnArmor: set_cmd( &cmd, aEnArmor); break;
@@ -606,6 +680,7 @@ main( int argc, char **argv )
 
          case oArmor: opt.armor = 1; opt.no_armor=0; break;
          case oOutput: opt.outfile = pargs.r.ret_str; break;
+         case oQuiet: opt.quiet = 1; break;
          case oVerbose: g10_opt_verbose++;
                    opt.verbose++; opt.list_sigs=1; break;
          case oKOption: set_cmd( &cmd, aKMode ); break;
@@ -636,8 +711,10 @@ main( int argc, char **argv )
          case oNoComment: opt.no_comment=1; break;
          case oCompletesNeeded: opt.completes_needed = pargs.r.ret_int; break;
          case oMarginalsNeeded: opt.marginals_needed = pargs.r.ret_int; break;
+         case oMaxCertDepth: opt.max_cert_depth = pargs.r.ret_int; break;
          case oTrustDBName: trustdb_name = pargs.r.ret_str; break;
          case oDefaultKey: opt.def_secret_key = pargs.r.ret_str; break;
+         case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
          case oNoOptions: break; /* no-options */
          case oHomedir: opt.homedir = pargs.r.ret_str; break;
          case oNoBatch: opt.batch = 0; break;
@@ -648,22 +725,31 @@ main( int argc, char **argv )
          case oCompressKeys: opt.compress_keys = 1; break;
          case aListSecretKeys: set_cmd( &cmd, aListSecretKeys); break;
          case oAlwaysTrust: opt.always_trust = 1; break;
-         case oLoadExtension: register_cipher_extension(pargs.r.ret_str); break;
-         case oRFC1991: opt.rfc1991 = 1; opt.no_comment = 1; break;
+         case oLoadExtension:
+           register_cipher_extension(orig_argc? *orig_argv:NULL,
+                                     pargs.r.ret_str);
+           break;
+         case oRFC1991:
+           opt.rfc1991 = 1;
+           opt.no_comment = 1;
+           opt.escape_from = 1;
+           break;
          case oEmuChecksumBug: opt.emulate_bugs |= EMUBUG_GPGCHKSUM; break;
-         case oDoNotExportRSA: opt.do_not_export_rsa = 1; break;
          case oCompressSigs: opt.compress_sigs = 1; break;
          case oRunAsShmCP:
-         #ifdef USE_SHM_COPROCESSING
-           opt.shm_coprocess = 1;
-           requested_shm_size = pargs.r.ret_ulong;
-         #else
+         #ifndef USE_SHM_COPROCESSING
+           /* not possible in the option file,
+            * but we print the warning here anyway */
            log_error("shared memory coprocessing is not available\n");
          #endif
            break;
          case oSetFilename: opt.set_filename = pargs.r.ret_str; break;
          case oComment: opt.comment_string = pargs.r.ret_str; break;
          case oThrowKeyid: opt.throw_keyid = 1; break;
+         case oForceV3Sigs: opt.force_v3_sigs = 1; break;
+         case oS2KMode:   opt.s2k_mode = pargs.r.ret_int; break;
+         case oS2KDigest: s2k_digest_string = m_strdup(pargs.r.ret_str); break;
+         case oS2KCipher: s2k_cipher_string = m_strdup(pargs.r.ret_str); break;
 
        #ifdef IS_G10
          case oRemote: /* store the remote users */
@@ -672,6 +758,7 @@ main( int argc, char **argv )
            sl->next = remusr;
            remusr = sl;
            break;
+         case oTextmodeShort: opt.textmode = 2; break;
          case oTextmode: opt.textmode=1;  break;
          case oUser: /* store the local users */
            sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
@@ -680,7 +767,7 @@ main( int argc, char **argv )
            locusr = sl;
            break;
          case oCompress: opt.compress = pargs.r.ret_int; break;
-         case oPasswdFD: set_passphrase_fd( pargs.r.ret_int ); break;
+         case oPasswdFD: pwfd = pargs.r.ret_int; break;
          case oCipherAlgo: def_cipher_string = m_strdup(pargs.r.ret_str); break;
          case oDigestAlgo: def_digest_string = m_strdup(pargs.r.ret_str); break;
          case oNoSecmemWarn: secmem_set_flags( secmem_get_flags() | 1 ); break;
@@ -690,8 +777,16 @@ main( int argc, char **argv )
          case oNoSecmemWarn:
            break;  /* dummies */
        #endif
+         case oCharset:
+           if( set_native_charset( pargs.r.ret_str ) )
+               log_error(_("%s is not a valid character set\n"),
+                                                   pargs.r.ret_str);
+           break;
+         case oNotDashEscaped: opt.not_dash_escaped = 1; break;
+         case oEscapeFrom: opt.escape_from = 1; break;
+         case oLockOnce: opt.lock_once = 1; break;
 
-         default : errors++; pargs.err = configfp? 1:2; break;
+         default : pargs.err = configfp? 1:2; break;
        }
     }
     if( configfp ) {
@@ -709,22 +804,7 @@ main( int argc, char **argv )
        tty_printf("%s\n", strusage(15) );
     }
 
-  #ifdef USE_SHM_COPROCESSING
-    if( opt.shm_coprocess ) {
-      #ifdef IS_G10
-       init_shm_coprocessing(requested_shm_size, 1 );
-      #else
-       init_shm_coprocessing(requested_shm_size, 0 );
-      #endif
-    }
-  #endif
-  #ifdef IS_G10
-    /* initialize the secure memory. */
-    secmem_init( 16384 );
-    maybe_setuid = 0;
-    /* Okay, we are now working under our real uid */
-  #endif
-
+    secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */
 
     set_debug();
 
@@ -742,12 +822,41 @@ main( int argc, char **argv )
        if( check_digest_algo(opt.def_digest_algo) )
            log_error(_("selected digest algorithm is invalid\n"));
     }
+    if( s2k_cipher_string ) {
+       opt.s2k_cipher_algo = string_to_cipher_algo(s2k_cipher_string);
+       m_free(s2k_cipher_string); s2k_cipher_string = NULL;
+       if( check_cipher_algo(opt.s2k_cipher_algo) )
+           log_error(_("selected cipher algorithm is invalid\n"));
+    }
+    if( s2k_digest_string ) {
+       opt.s2k_digest_algo = string_to_digest_algo(s2k_digest_string);
+       m_free(s2k_digest_string); s2k_digest_string = NULL;
+       if( check_digest_algo(opt.s2k_digest_algo) )
+           log_error(_("selected digest algorithm is invalid\n"));
+    }
     if( opt.def_compress_algo < 1 || opt.def_compress_algo > 2 )
        log_error(_("compress algorithm must be in range %d..%d\n"), 1, 2);
     if( opt.completes_needed < 1 )
        log_error(_("completes-needed must be greater than 0\n"));
     if( opt.marginals_needed < 2 )
        log_error(_("marginals-needed must be greater than 1\n"));
+    if( opt.max_cert_depth < 1 || opt.max_cert_depth > 255 )
+       log_error(_("max-cert-depth must be in range 1 to 255\n"));
+    switch( opt.s2k_mode ) {
+      case 0:
+       log_info(_("NOTE: simple S2K mode (0) is strongly discouraged\n"));
+       break;
+      case 1: case 3: break;
+      default:
+       log_error(_("invalid S2K mode; must be 0, 1 or 3\n"));
+    }
+
+    {  const char *p = strusage(13);
+       for( ; *p && (isdigit(*p) || *p=='.'); p++ )
+           ;
+       if( *p )
+           log_info("NOTE: this is a development version!\n");
+    }
 
     if( log_get_errorcount(0) )
        g10_exit(2);
@@ -772,7 +881,7 @@ main( int argc, char **argv )
 
 
     /* kludge to let -sat generate a clear text signature */
-    if( opt.textmode && !detached_sig && opt.armor && cmd == aSign )
+    if( opt.textmode == 2 && !detached_sig && opt.armor && cmd == aSign )
        cmd = aClearsign;
 
     if( opt.verbose > 1 )
@@ -784,31 +893,22 @@ main( int argc, char **argv )
        && !(cmd == aKMode && argc == 2 ) ) {
 
        if( !sec_nrings || default_keyring )  /* add default secret rings */
-           add_secret_keyring("secring.gpg");
+           add_keyblock_resource("secring.gpg", 0, 1);
        for(sl = sec_nrings; sl; sl = sl->next )
-           add_secret_keyring( sl->d );
+           add_keyblock_resource( sl->d, 0, 1 );
        if( !nrings || default_keyring )  /* add default ring */
-           add_keyring("pubring.gpg");
+           add_keyblock_resource("pubring.gpg", 0, 0);
        for(sl = nrings; sl; sl = sl->next )
-           add_keyring( sl->d );
+           add_keyblock_resource( sl->d, 0, 0 );
     }
     FREE_STRLIST(nrings);
     FREE_STRLIST(sec_nrings);
 
-    if( argc )
-       fname = *argv;
-    else {
-       fname = NULL;
-       if( get_passphrase_fd() == 0 ) {
-           /* reading data and passphrase from stdin:
-            * we assume the first line is the passphrase, so
-            * we should read it now.
-            *
-            * We should do it here, but for now it is not needed.
-            * Anyway, this password scheme is not quite good
-            */
-       }
-    }
+
+    if( pwfd != -1 )  /* read the passphrase now. */
+       read_passphrase_from_fd( pwfd );
+
+    fname = argc? *argv : NULL;
 
     switch( cmd ) {
       case aPrimegen:
@@ -817,6 +917,7 @@ main( int argc, char **argv )
       case aGenRandom:
       case aDeArmor:
       case aEnArmor:
+      case aFixTrustDB:
        break;
       case aKMode:
       case aListKeys:
@@ -912,9 +1013,17 @@ main( int argc, char **argv )
 
       case aSignKey: /* sign the key given as argument */
       case aEditKey: /* Edit a key signature */
-       if( argc != 1 )
-           wrong_args(_("--edit-key username"));
-       keyedit_menu(fname, locusr );
+       if( !argc )
+           wrong_args(_("--edit-key username [commands]"));
+       if( argc > 1 ) {
+           sl = NULL;
+           for( argc--, argv++ ; argc; argc--, argv++ )
+               append_to_strlist( &sl, *argv );
+           keyedit_menu( fname, locusr, sl );
+           free_strlist(sl);
+       }
+       else
+           keyedit_menu(fname, locusr, NULL );
        break;
 
       #endif /* IS_G10 */
@@ -953,7 +1062,7 @@ main( int argc, char **argv )
            else {
                /* add keyring (default keyrings are not registered in this
                 * special case */
-               add_keyring( argv[1] );
+               add_keyblock_resource( argv[1], 0, 0 );
                public_key_list( **argv?1:0, argv );
            }
        }
@@ -969,25 +1078,27 @@ main( int argc, char **argv )
        break;
     #endif
 
+      case aFastImport:
       case aImport:
        if( !argc  ) {
-           rc = import_keys( NULL );
+           rc = import_keys( NULL, (cmd == aFastImport) );
            if( rc )
                log_error("import failed: %s\n", g10_errstr(rc) );
        }
        for( ; argc; argc--, argv++ ) {
-           rc = import_keys( *argv );
+           rc = import_keys( *argv, (cmd == aFastImport) );
            if( rc )
-               log_error("import from '%s' failed: %s\n",
+               log_error("import from `%s' failed: %s\n",
                                                *argv, g10_errstr(rc) );
        }
        break;
 
       case aExport:
+      case aExportAll:
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist( &sl, *argv );
-       export_pubkeys( sl );
+       export_pubkeys( sl, (cmd == aExport) );
        free_strlist(sl);
        break;
 
@@ -1060,15 +1171,20 @@ main( int argc, char **argv )
        if( argc < 1 || argc > 2 )
            wrong_args("--gen-random level [hex]");
        {
+           int c;
            int level = atoi(*argv);
            for(;;) {
-               byte *p = get_random_bits( 8, level, 0);
-               if( argc == 1 ) {
+               byte *p;
+               if( argc == 2 ) {
+                   p = get_random_bits( 8, level, 0);
                    printf("%02x", *p );
                    fflush(stdout);
                }
-               else
-                   putchar(c&0xff);
+               else {
+                   p = get_random_bits( 800, level, 0);
+                   for(c=0; c < 100; c++ )
+                       putchar( p[c] );
+               }
                m_free(p);
            }
        }
@@ -1082,7 +1198,7 @@ main( int argc, char **argv )
            int algo = string_to_digest_algo(*argv);
 
            if( !algo )
-               log_error(_("invalid hash algorithm '%s'\n"), *argv );
+               log_error(_("invalid hash algorithm `%s'\n"), *argv );
            else {
                argc--; argv++;
                if( !argc )
@@ -1104,10 +1220,6 @@ main( int argc, char **argv )
        }
        break;
 
-     #ifdef MAINTAINER_OPTIONS
-      case aTest: do_test( argc? atoi(*argv): 1 ); break;
-      #endif /* MAINTAINER OPTIONS */
-
       case aListTrustDB:
        if( !argc )
            list_trustdb(NULL);
@@ -1117,6 +1229,12 @@ main( int argc, char **argv )
        }
        break;
 
+      case aUpdateTrustDB:
+       if( argc )
+           wrong_args("--update-trustdb");
+       update_trustdb();
+       break;
+
       case aCheckTrustDB:
        if( !argc )
            check_trustdb(NULL);
@@ -1126,10 +1244,17 @@ main( int argc, char **argv )
        }
        break;
 
+      case aFixTrustDB:
+       log_error("this command ist not yet implemented.\"\n");
+       log_error("A workaround is to use \"--export-ownertrust\", remove\n");
+       log_error("the trustdb file and do an \"--import-ownertrust\".\n" );
+       break;
+
       case aListTrustPath:
-       if( argc != 2 )
-           wrong_args("--list-trust-path [-- -]<maxdepth> <username>");
-       list_trust_path( atoi(*argv), argv[1] );
+       if( !argc )
+           wrong_args("--list-trust-path <usernames>");
+       for( ; argc; argc--, argv++ )
+           list_trust_path( *argv );
        break;
 
       case aExportOwnerTrust:
@@ -1153,9 +1278,15 @@ main( int argc, char **argv )
        /* fixme: g10maint should do regular maintenace tasks here */
        if( argc > 1 )
            wrong_args(_("[filename]"));
+       /* Issue some output for the unix newbie */
+       if( !fname && !opt.outfile && isatty( fileno(stdin) )
+               && isatty( fileno(stdout) ) && isatty( fileno(stderr) ) )
+           log_info(_("Go ahead and type your message ...\n"));
+
        if( !(a = iobuf_open(fname)) )
-           log_error(_("can't open '%s'\n"), print_fname_stdin(fname));
+           log_error(_("can't open `%s'\n"), print_fname_stdin(fname));
        else {
+
            if( !opt.no_armor ) {
                if( use_armor_filter( a ) ) {
                    memset( &afx, 0, sizeof afx);
@@ -1183,26 +1314,18 @@ main( int argc, char **argv )
 void
 g10_exit( int rc )
 {
+    if( opt.debug & DBG_MEMSTAT_VALUE )
+       m_print_stats("on exit");
     if( opt.debug )
        secmem_dump_stats();
     secmem_term();
-    rc = rc? rc : log_get_errorcount(0)? 2:0;
+    rc = rc? rc : log_get_errorcount(0)? 2 :
+                       g10_errors_seen? 1 : 0;
     /*write_status( STATUS_LEAVE );*/
     exit(rc );
 }
 
 
-void
-do_not_use_RSA()
-{
-    static int did_rsa_note = 0;
-
-    if( !did_rsa_note ) {
-       did_rsa_note = 1;
-       log_info(_("RSA keys are deprecated; please consider "
-                  "creating a new key and use this key in the future\n"));
-    }
-}
 
 
 #ifdef IS_G10MAINT
@@ -1308,12 +1431,5 @@ print_mds( const char *fname, int algo )
 
 
 
-#ifdef MAINTAINER_OPTIONS
-static void
-do_test(int times)
-{
-    m_check(NULL);
-}
-#endif /* MAINTAINER OPTIONS */
 #endif /* IS_G10MAINT */