Changes to make use of code taken from libassuan. This replaces the
[gnupg.git] / g10 / g10.c
index 5dff576..fefb8ab 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -1,5 +1,6 @@
 /* g10.c - The GnuPG utility (main for gpg)
- * Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ *               2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -32,6 +33,7 @@
 #ifdef HAVE_STAT
 #include <sys/stat.h> /* for stat() */
 #endif
+#include <fcntl.h>
 
 #define INCLUDED_BY_MAIN_MODULE 1
 #include "packet.h"
 #include "keyserver-internal.h"
 #include "exec.h"
 #include "cardglue.h"
+#ifdef ENABLE_CARD_SUPPORT
+#include "ccid-driver.h"
+#endif
+
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
+#define MY_O_BINARY  O_BINARY
+#ifndef S_IRGRP
+# define S_IRGRP 0
+# define S_IWGRP 0
+#endif
+#else
+#define MY_O_BINARY  0
+#endif
+
 
 enum cmd_and_opt_values
   {
@@ -74,22 +90,26 @@ enum cmd_and_opt_values
     oVerbose     = 'v',
     oCompress    = 'z',
     oSetNotation  = 'N',
+    aListSecretKeys = 'K',
     oBatch       = 500,
+    oMaxOutput,
     oSigNotation,
     oCertNotation,
     oShowNotation,
     oNoShowNotation,
     aEncrFiles,
-    aDecryptFiles,                          
+    aEncrSym,
+    aDecryptFiles,
     aClearsign,
     aStore,
     aKeygen,
     aSignEncr,
+    aSignEncrSym,
     aSignSym,
     aSignKey,
     aLSignKey,
-    aNRSignKey,
-    aNRLSignKey,
+    aListConfig,
+    aGPGConfList,
     aListPackets,
     aEditKey,
     aDeleteKeys,
@@ -103,12 +123,10 @@ enum cmd_and_opt_values
     aVerifyFiles,
     aListKeys,
     aListSigs,
-    aListSecretKeys,
     aSendKeys,
     aRecvKeys,
     aSearchKeys,
     aExport,
-    aExportAll,
     aExportSecret,
     aExportSecretSub,
     aCheckKeys,
@@ -143,11 +161,14 @@ enum cmd_and_opt_values
     oNoAskSigExpire,
     oAskCertExpire,
     oNoAskCertExpire,
+    oAskCertLevel,
+    oNoAskCertLevel,
     oFingerprint,
     oWithFingerprint,
     oAnswerYes,
     oAnswerNo,
-    oDefCertCheckLevel,
+    oDefCertLevel,
+    oMinCertLevel,
     oKeyring,
     oPrimaryKeyring,
     oSecretKeyring,
@@ -159,14 +180,11 @@ enum cmd_and_opt_values
     oOptions,
     oDebug,
     oDebugAll,
+    oDebugCCIDDriver,
     oStatusFD,
-#ifdef __riscos__
     oStatusFile,
-#endif /* __riscos__ */
     oAttributeFD,
-#ifdef __riscos__
     oAttributeFile,
-#endif /* __riscos__ */
     oSKComments,
     oNoSKComments,
     oEmitVersion,
@@ -183,22 +201,25 @@ enum cmd_and_opt_values
     oPGP6,
     oPGP7,
     oPGP8,
+    oRFC2440Text,
+    oNoRFC2440Text,
     oCipherAlgo,
     oDigestAlgo,
     oCertDigestAlgo,
     oCompressAlgo,
+    oCompressLevel,
+    oBZ2CompressLevel,
+    oBZ2DecompressLowmem,
     oPasswdFD,
-#ifdef __riscos__
     oPasswdFile,
-#endif /* __riscos__ */
     oCommandFD,
-#ifdef __riscos__
     oCommandFile,
-#endif /* __riscos__ */
     oQuickRandom,
     oNoVerbose,
     oTrustDBName,
     oNoSecmemWarn,
+    oRequireSecmem,
+    oNoRequireSecmem,
     oNoPermissionWarn,
     oNoMDCWarn,
     oNoArmor,
@@ -216,7 +237,6 @@ enum cmd_and_opt_values
     oAlwaysTrust,
     oTrustModel,
     oForceOwnertrust,
-    oEmuChecksumBug,
     oRunAsShmCP,
     oSetFilename,
     oForYourEyesOnly,
@@ -228,11 +248,12 @@ enum cmd_and_opt_values
     oNoShowPolicyURL,
     oSigKeyserverURL,
     oUseEmbeddedFilename,
+    oNoUseEmbeddedFilename,
     oComment,
     oDefaultComment,
     oNoComments,
-    oThrowKeyid,
-    oNoThrowKeyid,
+    oThrowKeyids,
+    oNoThrowKeyids,
     oShowPhotos,
     oNoShowPhotos,
     oPhotoViewer,
@@ -248,7 +269,7 @@ enum cmd_and_opt_values
     oS2KDigest,
     oS2KCipher,
     oSimpleSKChecksum,                          
-    oCharset,
+    oDisplayCharset,
     oNotDashEscaped,
     oEscapeFrom,
     oNoEscapeFrom,
@@ -267,9 +288,7 @@ enum cmd_and_opt_values
     oHiddenEncryptTo,
     oNoEncryptTo,
     oLoggerFD,
-#ifdef __riscos__
     oLoggerFile,
-#endif /* __riscos__ */
     oUtf8Strings,
     oNoUtf8Strings,
     oDisableCipherAlgo,
@@ -311,13 +330,13 @@ enum cmd_and_opt_values
     oPersonalCipherPreferences,
     oPersonalDigestPreferences,
     oPersonalCompressPreferences,
-    oEmuMDEncodeBug,
     oDisplay,
     oTTYname,
     oTTYtype,
     oLCctype,
     oLCmessages,
     oGroup,
+    oUnGroup,
     oNoGroups,
     oStrict,
     oNoStrict,
@@ -325,6 +344,7 @@ enum cmd_and_opt_values
     oNoMangleDosFilenames,
     oEnableProgressFilter,
     oMultifile,
+    oKeyidFormat,
 
     oReaderPort,
     octapiDriver,
@@ -362,8 +382,6 @@ static ARGPARSE_OPTS opts[] = {
                                    N_("remove keys from the secret keyring")},
     { aSignKey,  "sign-key"   ,256, N_("sign a key")},
     { aLSignKey, "lsign-key"  ,256, N_("sign a key locally")},
-    { aNRSignKey, "nrsign-key"  ,256, "@"},
-    { aNRLSignKey, "nrlsign-key"  ,256, "@"},
     { aEditKey,  "edit-key"   ,256, N_("sign or edit a key")},
     { aGenRevoke, "gen-revoke",256, N_("generate a revocation certificate")},
     { aDesigRevoke, "desig-revoke",256, "@" },
@@ -374,7 +392,6 @@ static ARGPARSE_OPTS opts[] = {
                                     N_("search for keys on a key server") },
     { aRefreshKeys, "refresh-keys", 256,
                                     N_("update all keys from a keyserver")},
-    { aExportAll, "export-all"    , 256, "@" },
     { aExportSecret, "export-secret-keys" , 256, "@" },
     { aExportSecretSub, "export-secret-subkeys" , 256, "@" },
     { aImport, "import",      256     , N_("import/merge keys")},
@@ -384,6 +401,8 @@ static ARGPARSE_OPTS opts[] = {
     { aCardEdit,   "card-edit",  256, N_("change data on a card")},
     { aChangePIN,  "change-pin", 256, N_("change a card's PIN")},
 #endif
+    { aListConfig, "list-config", 256, "@"},
+    { aGPGConfList, "gpgconf-list", 256, "@" },
     { aListPackets, "list-packets",256, "@"},
     { aExportOwnerTrust, "export-ownertrust", 256, "@"},
     { aImportOwnerTrust, "import-ownertrust", 256, "@"},
@@ -415,7 +434,10 @@ static ARGPARSE_OPTS opts[] = {
     { oHiddenEncryptTo, "hidden-encrypt-to", 2, "@" },
     { oNoEncryptTo, "no-encrypt-to", 0, "@" },
     { oUser, "local-user",2, N_("use this user-id to sign or decrypt")},
-    { oCompress, NULL,       1, N_("|N|set compress level N (0 disables)") },
+    { oCompress, NULL, 1, N_("|N|set compress level N (0 disables)") },
+    { oCompressLevel, "compress-level", 1, "@" },
+    { oBZ2CompressLevel, "bzip2-compress-level", 1, "@" },
+    { oBZ2DecompressLowmem, "bzip2-decompress-lowmem", 0, "@" },
     { oTextmodeShort, NULL,   0, "@"},
     { oTextmode, "textmode",  0, N_("use canonical text mode")},
     { oNoTextmode, "no-textmode",  0, "@"},
@@ -425,7 +447,10 @@ static ARGPARSE_OPTS opts[] = {
     { oNoAskSigExpire, "no-ask-sig-expire",   0, "@"},
     { oAskCertExpire, "ask-cert-expire",   0, "@"},
     { oNoAskCertExpire, "no-ask-cert-expire",   0, "@"},
+    { oAskCertLevel, "ask-cert-level",   0, "@"},
+    { oNoAskCertLevel, "no-ask-cert-level",   0, "@"},
     { oOutput, "output",    2, N_("use as output file")},
+    { oMaxOutput, "max-output", 16|4, "@" },
     { oVerbose, "verbose",   0, N_("verbose") },
     { oQuiet,  "quiet",   0, "@"},
     { oNoTTY, "no-tty", 0, "@"},
@@ -456,18 +481,15 @@ static ARGPARSE_OPTS opts[] = {
     { oExportOptions, "export-options",2,"@"},
     { oListOptions, "list-options",2,"@"},
     { oVerifyOptions, "verify-options",2,"@"},
-    { oCharset, "charset", 2, "@"},
+    { oDisplayCharset, "display-charset", 2, "@"},
+    { oDisplayCharset, "charset", 2, "@"},
     { oOptions, "options", 2, "@"},
     { oDebug, "debug"     ,4|16, "@"},
     { oDebugAll, "debug-all" ,0, "@"},
     { oStatusFD, "status-fd" ,1, "@"},
-#ifdef __riscos__
     { oStatusFile, "status-file" ,2, "@"},
-#endif /* __riscos__ */
     { oAttributeFD, "attribute-fd" ,1, "@" },
-#ifdef __riscos__
     { oAttributeFile, "attribute-file" ,2, "@" },
-#endif /* __riscos__ */
     { oNoSKComments, "no-sk-comments", 0,   "@"},
     { oSKComments, "sk-comments", 0,   "@"},
     { oCompletesNeeded, "completes-needed", 1, "@"},
@@ -487,6 +509,8 @@ static ARGPARSE_OPTS opts[] = {
     { oPGP6, "pgp6", 0, "@"},
     { oPGP7, "pgp7", 0, "@"},
     { oPGP8, "pgp8", 0, "@"},
+    { oRFC2440Text, "rfc2440-text", 0, "@"},
+    { oNoRFC2440Text, "no-rfc2440-text", 0, "@"},
     { oS2KMode, "s2k-mode", 1, "@"},
     { oS2KDigest, "s2k-digest-algo", 2, "@"},
     { oS2KCipher, "s2k-cipher-algo", 2, "@"},
@@ -495,8 +519,11 @@ static ARGPARSE_OPTS opts[] = {
     { oDigestAlgo, "digest-algo", 2, "@"},
     { oCertDigestAlgo, "cert-digest-algo", 2 , "@" },
     { oCompressAlgo,"compress-algo", 2, "@"},
-    { oThrowKeyid, "throw-keyid", 0, "@"},
-    { oNoThrowKeyid, "no-throw-keyid", 0, "@" },
+    { oCompressAlgo, "compression-algo", 2, "@"}, /* Alias */
+    { oThrowKeyids, "throw-keyid", 0, "@"},
+    { oThrowKeyids, "throw-keyids", 0, "@"},
+    { oNoThrowKeyids, "no-throw-keyid", 0, "@" },
+    { oNoThrowKeyids, "no-throw-keyids", 0, "@" },
     { oShowPhotos,   "show-photos", 0, "@" },
     { oNoShowPhotos, "no-show-photos", 0, "@" },
     { oPhotoViewer,  "photo-viewer", 2, "@" },
@@ -518,7 +545,6 @@ static ARGPARSE_OPTS opts[] = {
 
   /* hidden options */
     { aListOwnerTrust, "list-ownertrust", 256, "@"}, /* deprecated */
-    { oCompressAlgo, "compression-algo", 1, "@"}, /* alias */
     { aPrintMDs, "print-mds" , 256, "@"}, /* old */
     { aListTrustDB, "list-trustdb",0 , "@"},
     /* Not yet used */
@@ -526,17 +552,15 @@ static ARGPARSE_OPTS opts[] = {
     { aPipeMode,  "pipemode", 0, "@" },
     { oKOption, NULL,   0, "@"},
     { oPasswdFD, "passphrase-fd",1, "@" },
-#ifdef __riscos__
     { oPasswdFile, "passphrase-file",2, "@" },
-#endif /* __riscos__ */
     { oCommandFD, "command-fd",1, "@" },
-#ifdef __riscos__
     { oCommandFile, "command-file",2, "@" },
-#endif /* __riscos__ */
     { oQuickRandom, "quick-random", 0, "@"},
     { oNoVerbose, "no-verbose", 0, "@"},
     { oTrustDBName, "trustdb-name", 2, "@" },
-    { oNoSecmemWarn, "no-secmem-warning", 0, "@" }, /* used only by regression tests */
+    { oNoSecmemWarn, "no-secmem-warning", 0, "@" },
+    { oRequireSecmem,"require-secmem", 0, "@" },
+    { oNoRequireSecmem,"no-require-secmem", 0, "@" },
     { oNoPermissionWarn, "no-permission-warning", 0, "@" },
     { oNoMDCWarn, "no-mdc-warning", 0, "@" },
     { oNoArmor, "no-armor",   0, "@"},
@@ -554,11 +578,12 @@ static ARGPARSE_OPTS opts[] = {
     { oSkipVerify, "skip-verify",0, "@" },
     { oCompressKeys, "compress-keys",0, "@"},
     { oCompressSigs, "compress-sigs",0, "@"},
-    { oDefCertCheckLevel, "default-cert-check-level", 1, "@"},
+    { oDefCertLevel, "default-cert-check-level", 1, "@"}, /* Old option */
+    { oDefCertLevel, "default-cert-level", 1, "@"},
+    { oMinCertLevel, "min-cert-level", 1, "@"},
     { oAlwaysTrust, "always-trust", 0, "@"},
     { oTrustModel, "trust-model", 2, "@"},
     { oForceOwnertrust, "force-ownertrust", 2, "@"},
-    { oEmuChecksumBug, "emulate-checksum-bug", 0, "@"},
     { oRunAsShmCP, "run-as-shm-coprocess", 4, "@" },
     { oSetFilename, "set-filename", 2, "@" },
     { oForYourEyesOnly, "for-your-eyes-only", 0, "@" },
@@ -584,10 +609,9 @@ static ARGPARSE_OPTS opts[] = {
     { oLockMultiple, "lock-multiple", 0, "@" },
     { oLockNever, "lock-never", 0, "@" },
     { oLoggerFD, "logger-fd",1, "@" },
-#ifdef __riscos__
     { oLoggerFile, "logger-file",2, "@" },
-#endif /* __riscos__ */
     { oUseEmbeddedFilename, "use-embedded-filename", 0, "@" },
+    { oNoUseEmbeddedFilename, "no-use-embedded-filename", 0, "@" },
     { oUtf8Strings, "utf8-strings", 0, "@" },
     { oNoUtf8Strings, "no-utf8-strings", 0, "@" },
     { oWithFingerprint, "with-fingerprint", 0, "@" },
@@ -628,13 +652,18 @@ static ARGPARSE_OPTS opts[] = {
     { oPersonalCipherPreferences,  "personal-cipher-preferences", 2, "@"},
     { oPersonalDigestPreferences,  "personal-digest-preferences", 2, "@"},
     { oPersonalCompressPreferences,  "personal-compress-preferences", 2, "@"},
-    { oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
+    /* Aliases.  I constantly mistype these, and assume other people
+       do as well. */
+    { oPersonalCipherPreferences, "personal-cipher-prefs", 2, "@"},
+    { oPersonalDigestPreferences, "personal-digest-prefs", 2, "@"},
+    { oPersonalCompressPreferences, "personal-compress-prefs", 2, "@"},
     { oDisplay,    "display",     2, "@" },
     { oTTYname,    "ttyname",     2, "@" },
     { oTTYtype,    "ttytype",     2, "@" },
     { oLCctype,    "lc-ctype",    2, "@" },
     { oLCmessages, "lc-messages", 2, "@" },
     { oGroup,      "group",       2, "@" },
+    { oUnGroup,    "ungroup",     2, "@" },
     { oNoGroups,   "no-groups",    0, "@" },
     { oStrict,     "strict",      0, "@" },
     { oNoStrict,   "no-strict",   0, "@" },
@@ -642,15 +671,25 @@ static ARGPARSE_OPTS opts[] = {
     { oNoMangleDosFilenames, "no-mangle-dos-filenames", 0, "@" },
     { oEnableProgressFilter, "enable-progress-filter", 0, "@" },
     { oMultifile, "multifile", 0, "@" },
+    { oKeyidFormat, "keyid-format", 2, "@" },
 
     { oReaderPort, "reader-port",    2, "@"},
     { octapiDriver, "ctapi-driver",  2, "@"},
     { opcscDriver, "pcsc-driver",    2, "@"},
     { oDisableCCID, "disable-ccid", 0, "@"},
+#if defined(ENABLE_CARD_SUPPORT) && defined(HAVE_LIBUSB)
+    { oDebugCCIDDriver, "debug-ccid-driver", 0, "@"},
+#endif
 
+    {0,NULL,0,NULL}
+};
 
-{0} };
 
+#ifdef ENABLE_SELINUX_HACKS
+#define ALWAYS_ADD_KEYRINGS 1
+#else
+#define ALWAYS_ADD_KEYRINGS 0
+#endif
 
 
 int g10_errors_seen = 0;
@@ -667,10 +706,6 @@ static void add_notation_data( const char *string, int which );
 static void add_policy_url( const char *string, int which );
 static void add_keyserver_url( const char *string, int which );
 
-#ifdef __riscos__
-RISCOS_GLOBAL_STATICS("GnuPG Heap")
-#endif /* __riscos__ */
-
 const char *
 strusage( int level )
 {
@@ -684,6 +719,19 @@ strusage( int level )
       case 19: p =
            _("Please report bugs to <gnupg-bugs@gnu.org>.\n");
        break;
+
+#ifdef IS_DEVELOPMENT_VERSION
+      case 20:
+       p="NOTE: THIS IS A DEVELOPMENT VERSION!";
+       break;
+      case 21:
+       p="It is only intended for test purposes and should NOT be";
+       break;
+      case 22:
+       p="used in a production environment or with production keys!";
+       break;
+#endif
+
       case 1:
       case 40: p =
            _("Usage: gpg [options] [files] (-h for help)");
@@ -791,7 +839,7 @@ static void
 i18n_init(void)
 {
 #ifdef USE_SIMPLE_GETTEXT
-    set_gettext_file( PACKAGE );
+    set_gettext_file (PACKAGE, "Software\\GNU\\GnuPG");
 #else
 #ifdef ENABLE_NLS
     setlocale( LC_ALL, "" );
@@ -851,6 +899,76 @@ set_homedir (char *dir)
 }
 
 
+/* We set the screen dimensions for UI purposes.  Do not allow screens
+   smaller than 80x24 for the sake of simplicity. */
+static void
+set_screen_dimensions(void)
+{
+#ifndef _WIN32
+  char *str;
+
+  str=getenv("COLUMNS");
+  if(str)
+    opt.screen_columns=atoi(str);
+
+  str=getenv("LINES");
+  if(str)
+    opt.screen_lines=atoi(str);
+#endif
+
+  if(opt.screen_columns<80 || opt.screen_columns>255)
+    opt.screen_columns=80;
+
+  if(opt.screen_lines<24 || opt.screen_lines>255)
+    opt.screen_lines=24;
+}
+
+
+/* Helper to open a file FNAME either for reading or writing to be
+   used with --status-file etc functions.  Not generally useful but it
+   avoids the riscos specific functions and well some Windows people
+   might like it too.  Prints an error message and returns -1 on
+   error. On success the file descriptor is returned.  */
+static int
+open_info_file (const char *fname, int for_write)
+{
+#ifdef __riscos__
+  return riscos_fdopenfile (fname, for_write);
+#elif defined (ENABLE_SELINUX_HACKS)
+  /* We can't allow these even when testing for a secured filename
+     because files to be secured might not yet been secured.  This is
+     similar to the option file but in that case it is unlikely that
+     sensitive information may be retrieved by means of error
+     messages.  */
+  return -1;
+#else 
+  int fd;
+
+/*   if (is_secured_filename (fname)) */
+/*     { */
+/*       fd = -1; */
+/*       errno = EPERM; */
+/*     } */
+/*   else */
+/*     { */
+      do
+        {
+          if (for_write)
+            fd = open (fname, O_CREAT | O_TRUNC | O_WRONLY,
+                        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+          else
+            fd = open (fname, O_RDONLY | MY_O_BINARY);
+        }
+      while (fd == -1 && errno == EINTR);
+/*     } */
+  if ( fd == -1)
+    log_error ( for_write? _("can't create `%s': %s\n")
+                         : _("can't open `%s': %s\n"), fname, strerror(errno));
+  
+  return fd;
+#endif
+}
+
 static void
 set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
 {
@@ -866,8 +984,18 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
        cmd = aSignSym;
     else if( cmd == aSym && new_cmd == aSign )
        cmd = aSignSym;
+    else if( cmd == aSym && new_cmd == aEncr )
+       cmd = aEncrSym;
+    else if( cmd == aEncr && new_cmd == aSym )
+       cmd = aEncrSym;
     else if( cmd == aKMode && new_cmd == aSym )
        cmd = aKModeC;
+    else if (cmd == aSignEncr && new_cmd == aSym)
+        cmd = aSignEncrSym;
+    else if (cmd == aSignSym && new_cmd == aEncr)
+        cmd = aSignEncrSym;
+    else if (cmd == aEncrSym && new_cmd == aSign)
+        cmd = aSignEncrSym;
     else if(   ( cmd == aSign     && new_cmd == aClearsign )
             || ( cmd == aClearsign && new_cmd == aSign )  )
        cmd = aClearsign;
@@ -880,47 +1008,79 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
 }
 
 
-static void add_group(char *string)
+static void
+add_group(char *string)
 {
   char *name,*value;
   struct groupitem *item;
-  STRLIST values=NULL;
 
   /* Break off the group name */
   name=strsep(&string,"=");
   if(string==NULL)
     {
-      log_error(_("no = sign found in group definition \"%s\"\n"),name);
+      log_error(_("no = sign found in group definition `%s'\n"),name);
       return;
     }
 
   trim_trailing_ws(name,strlen(name));
 
+  /* Does this group already exist? */
+  for(item=opt.grouplist;item;item=item->next)
+    if(strcasecmp(item->name,name)==0)
+      break;
+
+  if(!item)
+    {
+      item=m_alloc(sizeof(struct groupitem));
+      item->name=name;
+      item->next=opt.grouplist;
+      item->values=NULL;
+      opt.grouplist=item;
+    }
+
   /* Break apart the values */
   while ((value= strsep(&string," \t")))
     {
       if (*value)
-        add_to_strlist2 (&values,value,utf8_strings);
+        add_to_strlist2(&item->values,value,utf8_strings);
     }
+}
 
-  item=m_alloc(sizeof(struct groupitem));
-  item->name=name;
-  item->values=values;
-  item->next=opt.grouplist;
 
-  opt.grouplist=item;
+static void
+rm_group(char *name)
+{
+  struct groupitem *item,*last=NULL;
+
+  trim_trailing_ws(name,strlen(name));
+
+  for(item=opt.grouplist;item;last=item,item=item->next)
+    {
+      if(strcasecmp(item->name,name)==0)
+       {
+         if(last)
+           last->next=item->next;
+         else
+           opt.grouplist=item->next;
+
+         free_strlist(item->values);
+         m_free(item);
+         break;
+       }
+    }
 }
 
+
 /* We need to check three things.
 
    0) The homedir.  It must be x00, a directory, and owned by the
    user.
 
-   1) The options file.  Okay unless it or its containing directory is
-   group or other writable or not owned by us.  disable exec in this
-   case.
+   1) The options/gpg.conf file.  Okay unless it or its containing
+   directory is group or other writable or not owned by us.  Disable
+   exec in this case.
 
-   2) Extensions.  Same as #2.
+   2) Extensions.  Same as #1.
 
    Returns true if the item is unsafe. */
 static int
@@ -1055,50 +1215,50 @@ check_permissions(const char *path,int item)
       if(own)
        {
          if(item==0)
-           log_info(_("WARNING: unsafe ownership on "
-                      "homedir \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe ownership on"
+                      " homedir `%s'\n"),tmppath);
          else if(item==1)
-           log_info(_("WARNING: unsafe ownership on "
-                      "configuration file \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe ownership on"
+                      " configuration file `%s'\n"),tmppath);
          else
-           log_info(_("WARNING: unsafe ownership on "
-                      "extension \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe ownership on"
+                      " extension `%s'\n"),tmppath);
        }
       if(perm)
        {
          if(item==0)
-           log_info(_("WARNING: unsafe permissions on "
-                      "homedir \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe permissions on"
+                      " homedir `%s'\n"),tmppath);
          else if(item==1)
-           log_info(_("WARNING: unsafe permissions on "
-                      "configuration file \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe permissions on"
+                      " configuration file `%s'\n"),tmppath);
          else
-           log_info(_("WARNING: unsafe permissions on "
-                      "extension \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe permissions on"
+                      " extension `%s'\n"),tmppath);
        }
       if(enc_dir_own)
        {
          if(item==0)
-           log_info(_("WARNING: unsafe enclosing directory ownership on "
-                      "homedir \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe enclosing directory ownership on"
+                      " homedir `%s'\n"),tmppath);
          else if(item==1)
-           log_info(_("WARNING: unsafe enclosing directory ownership on "
-                      "configuration file \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe enclosing directory ownership on"
+                      " configuration file `%s'\n"),tmppath);
          else
-           log_info(_("WARNING: unsafe enclosing directory ownership on "
-                      "extension \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe enclosing directory ownership on"
+                      " extension `%s'\n"),tmppath);
        }
       if(enc_dir_perm)
        {
          if(item==0)
-           log_info(_("WARNING: unsafe enclosing directory permissions on "
-                      "homedir \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe enclosing directory permissions on"
+                      " homedir `%s'\n"),tmppath);
          else if(item==1)
-           log_info(_("WARNING: unsafe enclosing directory permissions on "
-                      "configuration file \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe enclosing directory permissions on"
+                      " configuration file `%s'\n"),tmppath);
          else
-           log_info(_("WARNING: unsafe enclosing directory permissions on "
-                      "extension \"%s\"\n"),tmppath);
+           log_info(_("WARNING: unsafe enclosing directory permissions on"
+                      " extension `%s'\n"),tmppath);
        }
     }
 
@@ -1115,6 +1275,308 @@ check_permissions(const char *path,int item)
   return 0;
 }
 
+
+static void
+print_algo_numbers(int (*checker)(int))
+{
+  int i,first=1;
+
+  for(i=0;i<=110;i++)
+    {
+      if(!checker(i))
+       {
+         if(first)
+           first=0;
+         else
+           printf(";");
+         printf("%d",i);
+       }
+    }
+}
+
+
+/* In the future, we can do all sorts of interesting configuration
+   output here.  For now, just give "group" as the Enigmail folks need
+   it, and pubkey, cipher, hash, and compress as they may be useful
+   for frontends. */
+static void
+list_config(char *items)
+{
+  int show_all=(items==NULL);
+  char *name=NULL;
+
+  if(!opt.with_colons)
+    return;
+
+  while(show_all || (name=strsep(&items," ")))
+    {
+      int any=0;
+
+      if(show_all || ascii_strcasecmp(name,"group")==0)
+       {
+         struct groupitem *iter;
+
+         for(iter=opt.grouplist;iter;iter=iter->next)
+           {
+             STRLIST sl;
+
+             printf("cfg:group:");
+             print_string(stdout,iter->name,strlen(iter->name),':');
+             printf(":");
+
+             for(sl=iter->values;sl;sl=sl->next)
+               {
+                 print_string2(stdout,sl->d,strlen(sl->d),':',';');
+                 if(sl->next)
+                   printf(";");
+               }
+
+             printf("\n");
+           }
+
+         any=1;
+       }
+
+      if(show_all || ascii_strcasecmp(name,"version")==0)
+       {
+         printf("cfg:version:");
+         print_string(stdout,VERSION,strlen(VERSION),':');
+         printf("\n");
+         any=1;
+       }
+
+      if(show_all || ascii_strcasecmp(name,"pubkey")==0)
+       {
+         printf("cfg:pubkey:");
+         print_algo_numbers(check_pubkey_algo);
+         printf("\n");
+         any=1;
+       }
+
+      if(show_all || ascii_strcasecmp(name,"cipher")==0)
+       {
+         printf("cfg:cipher:");
+         print_algo_numbers(check_cipher_algo);
+         printf("\n");
+         any=1;
+       }
+
+      if(show_all
+        || ascii_strcasecmp(name,"digest")==0
+        || ascii_strcasecmp(name,"hash")==0)
+       {
+         printf("cfg:digest:");
+         print_algo_numbers(check_digest_algo);
+         printf("\n");
+         any=1;
+       }
+
+      if(show_all || ascii_strcasecmp(name,"compress")==0)
+       {
+         printf("cfg:compress:");
+         print_algo_numbers(check_compress_algo);
+         printf("\n");
+         any=1;
+       }
+
+      if(show_all || ascii_strcasecmp(name,"ccid-reader-id")==0)
+       {
+#if defined(ENABLE_CARD_SUPPORT) && defined(HAVE_LIBUSB)
+          char *p, *p2, *list = ccid_get_reader_list ();
+
+          for (p=list; p && (p2 = strchr (p, '\n')); p = p2+1)
+            {
+              *p2 = 0;
+              printf("cfg:ccid-reader-id:%s\n", p);
+            }
+          free (list);
+#endif
+         any=1;
+       }
+
+      if(show_all)
+       break;
+
+      if(!any)
+       log_error(_("unknown configuration item `%s'\n"),name);
+    }
+}
+
+
+/* List options and default values in the GPG Conf format.  This is a
+   new tool distributed with gnupg 1.9.x but we also want some limited
+   support in older gpg versions.  The output is the name of the
+   configuration file and a list of options available for editing by
+   gpgconf.  */
+static void
+gpgconf_list (const char *configfile)
+{
+  /* The following definitions are taken from gnupg/tools/gpgconf-comp.c.  */
+#define GC_OPT_FLAG_NONE       0UL
+#define GC_OPT_FLAG_DEFAULT    (1UL << 4)
+
+  printf ("gpgconf-gpg.conf:%lu:\"%s\n",
+          GC_OPT_FLAG_DEFAULT,configfile?configfile:"/dev/null");
+  printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE);
+  printf ("quiet:%lu:\n",   GC_OPT_FLAG_NONE);
+  printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE);
+  printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE);
+}
+
+
+static int
+parse_subpacket_list(char *list)
+{
+  char *tok;
+  byte subpackets[128],i;
+  int count=0;
+
+  if(!list)
+    {
+      /* No arguments means all subpackets */
+      memset(subpackets+1,1,sizeof(subpackets)-1);
+      count=127;
+    }
+  else
+    {
+      memset(subpackets,0,sizeof(subpackets));
+
+      /* Merge with earlier copy */
+      if(opt.show_subpackets)
+       {
+         byte *in;
+
+         for(in=opt.show_subpackets;*in;in++)
+           {
+             if(*in>127 || *in<1)
+               BUG();
+
+             if(!subpackets[*in])
+               count++;
+             subpackets[*in]=1;
+           }
+       }
+
+      while((tok=strsep(&list," ,")))
+       {
+         if(!*tok)
+           continue;
+
+         i=atoi(tok);
+         if(i>127 || i<1)
+           return 0;
+
+         if(!subpackets[i])
+           count++;
+         subpackets[i]=1;
+       }
+    }
+
+  m_free(opt.show_subpackets);
+  opt.show_subpackets=m_alloc(count+1);
+  opt.show_subpackets[count--]=0;
+
+  for(i=1;i<128 && count>=0;i++)
+    if(subpackets[i])
+      opt.show_subpackets[count--]=i;
+
+  return 1;
+}
+
+
+static int
+parse_list_options(char *str)
+{
+  char *subpackets=""; /* something that isn't NULL */
+  struct parse_options lopts[]=
+    {
+      {"show-photos",LIST_SHOW_PHOTOS,NULL},
+      {"show-policy-urls",LIST_SHOW_POLICY_URLS,NULL},
+      {"show-notations",LIST_SHOW_NOTATIONS,NULL},
+      {"show-std-notations",LIST_SHOW_STD_NOTATIONS,NULL},
+      {"show-standard-notations",LIST_SHOW_STD_NOTATIONS,NULL},
+      {"show-user-notations",LIST_SHOW_USER_NOTATIONS,NULL},
+      {"show-keyserver-urls",LIST_SHOW_KEYSERVER_URLS,NULL},
+      {"show-uid-validity",LIST_SHOW_UID_VALIDITY,NULL},
+      {"show-unusable-uids",LIST_SHOW_UNUSABLE_UIDS,NULL},
+      {"show-unusable-subkeys",LIST_SHOW_UNUSABLE_SUBKEYS,NULL},
+      {"show-keyring",LIST_SHOW_KEYRING,NULL},
+      {"show-sig-expire",LIST_SHOW_SIG_EXPIRE,NULL},
+      {"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL},
+      {NULL,0,NULL}
+    };
+
+  /* C99 allows for non-constant initializers, but we'd like to
+     compile everywhere, so fill in the show-sig-subpackets argument
+     here.  Note that if the parse_options array changes, we'll have
+     to change the subscript here. */
+  lopts[12].value=&subpackets;
+
+  if(parse_options(str,&opt.list_options,lopts,1))
+    {
+      if(opt.list_options&LIST_SHOW_SIG_SUBPACKETS)
+       {
+         /* Unset so users can pass multiple lists in. */
+         opt.list_options&=~LIST_SHOW_SIG_SUBPACKETS;
+         if(!parse_subpacket_list(subpackets))
+           return 0;
+       }
+      else if(subpackets==NULL && opt.show_subpackets)
+       {
+         /* User did 'no-show-subpackets' */
+         m_free(opt.show_subpackets);
+         opt.show_subpackets=NULL;
+       }
+
+      return 1;
+    }
+  else
+    return 0;
+}
+
+
+/* Collapses argc/argv into a single string that must be freed */
+static char *
+collapse_args(int argc,char *argv[])
+{
+  char *str=NULL;
+  int i,first=1,len=0;
+
+  for(i=0;i<argc;i++)
+    {
+      len+=strlen(argv[i])+2;
+      str=m_realloc(str,len);
+      if(first)
+       {
+         str[0]='\0';
+         first=0;
+       }
+      else
+       strcat(str," ");
+
+      strcat(str,argv[i]);
+    }
+
+  return str;
+}
+
+static void
+parse_trust_model(const char *model)
+{
+  if(ascii_strcasecmp(model,"pgp")==0)
+    opt.trust_model=TM_PGP;
+  else if(ascii_strcasecmp(model,"classic")==0)
+    opt.trust_model=TM_CLASSIC;
+  else if(ascii_strcasecmp(model,"always")==0)
+    opt.trust_model=TM_ALWAYS;
+  else if(ascii_strcasecmp(model,"direct")==0)
+    opt.trust_model=TM_DIRECT;
+  else if(ascii_strcasecmp(model,"auto")==0)
+    opt.trust_model=TM_AUTO;
+  else
+    log_error("unknown trust model `%s'\n",model);
+}
+
 int
 main( int argc, char **argv )
 {
@@ -1132,6 +1594,7 @@ main( int argc, char **argv )
     int detached_sig = 0;
     FILE *configfp = NULL;
     char *configname = NULL;
+    char *save_configname = NULL;
     unsigned configlineno;
     int parse_debug = 0;
     int default_config = 1;
@@ -1143,7 +1606,7 @@ main( int argc, char **argv )
     const char *trustdb_name = NULL;
     char *def_cipher_string = NULL;
     char *def_digest_string = NULL;
-    char *def_compress_string = NULL;
+    char *compress_algo_string = NULL;
     char *cert_digest_string = NULL;
     char *s2k_cipher_string = NULL;
     char *s2k_digest_string = NULL;
@@ -1155,12 +1618,12 @@ main( int argc, char **argv )
     int pwfd = -1;
     int with_fpr = 0; /* make an option out of --fingerprint */
     int any_explicit_recipient = 0;
+    int require_secmem=0,got_secmem=0;
 #ifdef USE_SHM_COPROCESSING
     ulong requested_shm_size=0;
 #endif
 
 #ifdef __riscos__
-    riscos_global_defaults();
     opt.lock_once = 1;
 #endif /* __riscos__ */
 
@@ -1177,14 +1640,14 @@ main( int argc, char **argv )
     create_dotlock(NULL); /* register locking cleanup */
     i18n_init();
     opt.command_fd = -1; /* no command fd */
-    opt.compress = -1; /* defaults to standard compress level */
+    opt.compress_level = -1; /* defaults to standard compress level */
+    opt.bz2_compress_level = -1; /* defaults to standard compress level */
     /* note: if you change these lines, look at oOpenPGP */
     opt.def_cipher_algo = 0;
     opt.def_digest_algo = 0;
     opt.cert_digest_algo = 0;
-    opt.def_compress_algo = -1;
+    opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */
     opt.s2k_mode = 3; /* iterated+salted */
-    opt.s2k_digest_algo = DIGEST_ALGO_SHA1;
 #ifdef USE_CAST5
     opt.s2k_cipher_algo = CIPHER_ALGO_CAST5;
 #else
@@ -1197,26 +1660,28 @@ main( int argc, char **argv )
     opt.force_v3_sigs = 1;
     opt.escape_from = 1;
     opt.import_options=IMPORT_SK2PK;
-    opt.export_options=
-      EXPORT_INCLUDE_NON_RFC|EXPORT_INCLUDE_ATTRIBUTES;
+    opt.export_options=EXPORT_ATTRIBUTES;
     opt.keyserver_options.import_options=IMPORT_REPAIR_PKS_SUBKEY_BUG;
-    opt.keyserver_options.export_options=
-      EXPORT_INCLUDE_NON_RFC|EXPORT_INCLUDE_ATTRIBUTES;
-    opt.keyserver_options.include_subkeys=1;
-    opt.keyserver_options.include_revoked=1;
-    opt.keyserver_options.try_dns_srv=1;
+    opt.keyserver_options.export_options=EXPORT_ATTRIBUTES;
+    opt.keyserver_options.options=
+      KEYSERVER_INCLUDE_SUBKEYS|KEYSERVER_INCLUDE_REVOKED|KEYSERVER_TRY_DNS_SRV|KEYSERVER_HONOR_KEYSERVER_URL;
     opt.verify_options=
-      VERIFY_SHOW_POLICY|VERIFY_SHOW_NOTATION|VERIFY_SHOW_KEYSERVER;
+      VERIFY_SHOW_POLICY_URLS|VERIFY_SHOW_STD_NOTATIONS|VERIFY_SHOW_KEYSERVER_URLS;
     opt.trust_model=TM_AUTO;
-    opt.mangle_dos_filenames = 0;
-#if defined (_WIN32)
-    set_homedir ( read_w32_registry_string( NULL,
-                                    "Software\\GNU\\GnuPG", "HomeDir" ));
+    opt.mangle_dos_filenames=0;
+    opt.min_cert_level=2;
+    set_screen_dimensions();
+    opt.keyid_format=KF_SHORT;
+    opt.rfc2440_text=1;
+    set_homedir ( default_homedir () );
+
+#ifdef ENABLE_CARD_SUPPORT
+# ifdef _WIN32
+    opt.pcsc_driver = "winscard.dll"; 
 #else
-    set_homedir ( getenv("GNUPGHOME") );
+    opt.pcsc_driver = "libpcsclite.so"; 
 #endif
-    if( !*opt.homedir )
-       set_homedir ( GNUPG_HOMEDIR );
+#endif /*ENABLE_CARD_SUPPORT*/
 
     /* check whether we have a config file on the commandline */
     orig_argc = argc;
@@ -1280,23 +1745,50 @@ main( int argc, char **argv )
     }
 #endif
     /* initialize the secure memory. */
-    secmem_init( 32768 );
+    got_secmem=secmem_init( 32768 );
     maybe_setuid = 0;
     /* Okay, we are now working under our real uid */
 
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+    /* There should be no way to get to this spot while still carrying
+       setuid privs.  Just in case, bomb out if we are. */
+    if(getuid()!=geteuid())
+      BUG();
+#endif
+
     set_native_charset (NULL); /* Try to auto set the character set */
 
+    /* Try for a version specific config file first */
     if( default_config )
       {
-       /* Try for a version specific config file first */
-       configname = make_filename(opt.homedir,
-                                  "gpg" EXTSEP_S "conf-" SAFE_VERSION, NULL );
-       if(access(configname,R_OK))
+       char *name=m_strdup("gpg" EXTSEP_S "conf-" SAFE_VERSION);
+       char *ver=&name[strlen("gpg" EXTSEP_S "conf-")];
+
+       do
          {
-           m_free(configname);
-           configname = make_filename(opt.homedir,
-                                      "gpg" EXTSEP_S "conf", NULL );
+           if(configname)
+             {
+               char *tok;
+
+               m_free(configname);
+               configname=NULL;
+
+               if((tok=strrchr(ver,SAFE_VERSION_DASH)))
+                 *tok='\0';
+               else if((tok=strrchr(ver,SAFE_VERSION_DOT)))
+                 *tok='\0';
+               else
+                 break;
+             }
+
+           configname = make_filename(opt.homedir,name,NULL);
          }
+       while(access(configname,R_OK));
+
+       m_free(name);
+
+       if(!configname)
+         configname=make_filename(opt.homedir, "gpg" EXTSEP_S "conf", NULL );
         if (!access (configname, R_OK))
           { /* Print a warning when both config files are present. */
             char *p = make_filename(opt.homedir, "options", NULL );
@@ -1334,6 +1826,12 @@ main( int argc, char **argv )
 
        configlineno = 0;
        configfp = fopen( configname, "r" );
+        if (configfp && is_secured_file (fileno (configfp)))
+          {
+            fclose (configfp);
+            configfp = NULL;
+            errno = EPERM;
+          }
        if( !configfp ) {
            if( default_config ) {
                if( parse_debug )
@@ -1357,22 +1855,27 @@ main( int argc, char **argv )
       {
        switch( pargs.r_opt )
          {
-         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 aSendKeys: set_cmd( &cmd, aSendKeys); break;
-         case aRecvKeys: set_cmd( &cmd, aRecvKeys); break;
-         case aSearchKeys: set_cmd( &cmd, aSearchKeys); break;
-         case aRefreshKeys: set_cmd( &cmd, aRefreshKeys); break;
-         case aExport: set_cmd( &cmd, aExport); break;
-         case aExportAll: set_cmd( &cmd, aExportAll); break;
+         case aCheckKeys: 
+         case aListConfig:
+          case aGPGConfList:
+         case aListPackets:
+         case aImport: 
+         case aFastImport: 
+         case aSendKeys: 
+         case aRecvKeys: 
+         case aSearchKeys:
+         case aRefreshKeys:
+         case aExport: 
+            set_cmd (&cmd, pargs.r_opt);
+            break;
          case aListKeys: set_cmd( &cmd, aListKeys); break;
          case aListSigs: set_cmd( &cmd, aListSigs); break;
          case aExportSecret: set_cmd( &cmd, aExportSecret); break;
          case aExportSecretSub: set_cmd( &cmd, aExportSecretSub); break;
-         case aDeleteSecretKeys: set_cmd( &cmd, aDeleteSecretKeys);
-                                                       greeting=1; break;
+         case aDeleteSecretKeys:
+           set_cmd( &cmd, aDeleteSecretKeys);
+           greeting=1;
+           break;
          case aDeleteSecretAndPublicKeys:
             set_cmd( &cmd, aDeleteSecretAndPublicKeys);
             greeting=1; 
@@ -1395,8 +1898,6 @@ main( int argc, char **argv )
          case aKeygen: set_cmd( &cmd, aKeygen); greeting=1; break;
          case aSignKey: set_cmd( &cmd, aSignKey); break;
          case aLSignKey: set_cmd( &cmd, aLSignKey); break;
-         case aNRSignKey: set_cmd( &cmd, aNRSignKey); break;
-         case aNRLSignKey: set_cmd( &cmd, aNRLSignKey); break;
          case aStore: set_cmd( &cmd, aStore); break;
          case aEditKey: set_cmd( &cmd, aEditKey); greeting=1; break;
          case aClearsign: set_cmd( &cmd, aClearsign); break;
@@ -1435,6 +1936,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 oMaxOutput: opt.max_output = pargs.r.ret_ulong; break;
          case oQuiet: opt.quiet = 1; break;
          case oNoTTY: tty_no_terminal(1); break;
          case oDryRun: opt.dry_run = 1; break;
@@ -1443,6 +1945,7 @@ main( int argc, char **argv )
            g10_opt_verbose++;
            opt.verbose++;
            opt.list_options|=LIST_SHOW_UNUSABLE_UIDS;
+           opt.list_options|=LIST_SHOW_UNUSABLE_SUBKEYS;
            break;
          case oKOption: set_cmd( &cmd, aKMode ); break;
 
@@ -1471,37 +1974,38 @@ main( int argc, char **argv )
            break;
          case oDebug: opt.debug |= pargs.r.ret_ulong; break;
          case oDebugAll: opt.debug = ~0; break;
+          case oDebugCCIDDriver: 
+#if defined(ENABLE_CARD_SUPPORT) && defined(HAVE_LIBUSB)
+            ccid_set_debug_level (1);
+#endif
+            break;
          case oStatusFD:
             set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) );
             break;
-#ifdef __riscos__
          case oStatusFile:
-            set_status_fd( iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 1), 1) );
+            set_status_fd ( open_info_file (pargs.r.ret_str, 1) );
             break;
-#endif /* __riscos__ */
          case oAttributeFD:
             set_attrib_fd(iobuf_translate_file_handle (pargs.r.ret_int, 1));
             break;
-#ifdef __riscos__
          case oAttributeFile:
-            set_attrib_fd(iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 1), 1) );
+            set_attrib_fd ( open_info_file (pargs.r.ret_str, 1) );
             break;
-#endif /* __riscos__ */
          case oLoggerFD:
             log_set_logfile( NULL,
-                             iobuf_translate_file_handle (pargs.r.ret_int, 1) );
+                             iobuf_translate_file_handle (pargs.r.ret_int, 1));
             break;
-#ifdef __riscos__
          case oLoggerFile:
-            log_set_logfile( NULL,
-                             iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 1), 1) );
+            log_set_logfile( NULL, open_info_file (pargs.r.ret_str, 1) );
             break;
-#endif /* __riscos__ */
+
          case oWithFingerprint:
             opt.with_fingerprint = 1;
             with_fpr=1; /*fall thru*/
          case oFingerprint: opt.fingerprint++; break;
-         case oSecretKeyring: append_to_strlist( &sec_nrings, pargs.r.ret_str); break;
+         case oSecretKeyring:
+            append_to_strlist( &sec_nrings, pargs.r.ret_str);
+            break;
          case oOptions:
            /* config files may not be nested (silently ignore them) */
            if( !configfp ) {
@@ -1512,7 +2016,8 @@ main( int argc, char **argv )
            break;
          case oNoArmor: opt.no_armor=1; opt.armor=0; break;
          case oNoDefKeyring: default_keyring = 0; break;
-          case oDefCertCheckLevel: opt.def_cert_check_level=pargs.r.ret_int; break;
+          case oDefCertLevel: opt.def_cert_level=pargs.r.ret_int; break;
+          case oMinCertLevel: opt.min_cert_level=pargs.r.ret_int; break;
          case oNoGreeting: nogreeting = 1; break;
          case oNoVerbose: g10_opt_verbose = 0;
                           opt.verbose = 0; opt.list_sigs=0; break;
@@ -1552,16 +2057,7 @@ main( int argc, char **argv )
               time. */
          case oAlwaysTrust: opt.trust_model=TM_ALWAYS; break;
          case oTrustModel:
-           if(ascii_strcasecmp(pargs.r.ret_str,"pgp")==0)
-             opt.trust_model=TM_PGP;
-           else if(ascii_strcasecmp(pargs.r.ret_str,"classic")==0)
-             opt.trust_model=TM_CLASSIC;
-           else if(ascii_strcasecmp(pargs.r.ret_str,"always")==0)
-             opt.trust_model=TM_ALWAYS;
-           else if(ascii_strcasecmp(pargs.r.ret_str,"auto")==0)
-             opt.trust_model=TM_AUTO;
-           else
-             log_error("unknown trust model \"%s\"\n",pargs.r.ret_str);
+           parse_trust_model(pargs.r.ret_str);
            break;
          case oForceOwnertrust:
            log_info(_("NOTE: %s is not for normal use!\n"),
@@ -1569,7 +2065,7 @@ main( int argc, char **argv )
            opt.force_ownertrust=string_to_trust_value(pargs.r.ret_str);
            if(opt.force_ownertrust==-1)
              {
-               log_error("invalid ownertrust \"%s\"\n",pargs.r.ret_str);
+               log_error("invalid ownertrust `%s'\n",pargs.r.ret_str);
                opt.force_ownertrust=0;
              }
            break;
@@ -1577,8 +2073,8 @@ main( int argc, char **argv )
 #ifndef __riscos__
 #if defined(USE_DYNAMIC_LINKING) || defined(_WIN32)
            if(check_permissions(pargs.r.ret_str,2))
-             log_info(_("cipher extension \"%s\" not loaded due to "
-                        "unsafe permissions\n"),pargs.r.ret_str);
+             log_info(_("cipher extension `%s' not loaded due to"
+                        " unsafe permissions\n"),pargs.r.ret_str);
            else
              register_cipher_extension(orig_argc? *orig_argv:NULL,
                                        pargs.r.ret_str);
@@ -1592,23 +2088,24 @@ main( int argc, char **argv )
            opt.force_v4_certs = 0;
            opt.escape_from = 1;
            break;
-         case oRFC2440:
          case oOpenPGP:
-           /* TODO: When 2440bis becomes a RFC, these may need
-               changing. */
+         case oRFC2440:
+           /* TODO: When 2440bis becomes a RFC, set new values for
+              oOpenPGP. */
+           opt.rfc2440_text=1;
            opt.compliance = CO_RFC2440;
            opt.allow_non_selfsigned_uid = 1;
            opt.allow_freeform_uid = 1;
            opt.pgp2_workarounds = 0;
            opt.escape_from = 0;
            opt.force_v3_sigs = 0;
-           opt.compress_keys = 0;          /* not mandated  but we do it */
+           opt.compress_keys = 0;          /* not mandated, but we do it */
            opt.compress_sigs = 0;          /* ditto. */
            opt.not_dash_escaped = 0;
            opt.def_cipher_algo = 0;
            opt.def_digest_algo = 0;
            opt.cert_digest_algo = 0;
-           opt.def_compress_algo = -1;
+           opt.compress_algo = -1;
             opt.s2k_mode = 3; /* iterated+salted */
            opt.s2k_digest_algo = DIGEST_ALGO_SHA1;
            opt.s2k_cipher_algo = CIPHER_ALGO_3DES;
@@ -1618,8 +2115,9 @@ main( int argc, char **argv )
          case oPGP7:  opt.compliance = CO_PGP7;  break;
          case oPGP8:  opt.compliance = CO_PGP8;  break;
          case oGnuPG: opt.compliance = CO_GNUPG; break;
-         case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break;
          case oCompressSigs: opt.compress_sigs = 1; break;
+         case oRFC2440Text: opt.rfc2440_text=1; break;
+         case oNoRFC2440Text: opt.rfc2440_text=0; break;
          case oRunAsShmCP:
 #ifndef __riscos__
 # ifndef USE_SHM_COPROCESSING
@@ -1642,23 +2140,27 @@ main( int argc, char **argv )
          case oCertPolicyURL: add_policy_url(pargs.r.ret_str,1); break;
           case oShowPolicyURL:
            deprecated_warning(configname,configlineno,"--show-policy-url",
-                              "--list-options ","show-policy-url");
+                              "--list-options ","show-policy-urls");
            deprecated_warning(configname,configlineno,"--show-policy-url",
-                              "--verify-options ","show-policy-url");
-           opt.list_options|=LIST_SHOW_POLICY;
-           opt.verify_options|=VERIFY_SHOW_POLICY;
+                              "--verify-options ","show-policy-urls");
+           opt.list_options|=LIST_SHOW_POLICY_URLS;
+           opt.verify_options|=VERIFY_SHOW_POLICY_URLS;
            break;
          case oNoShowPolicyURL:
            deprecated_warning(configname,configlineno,"--no-show-policy-url",
-                              "--list-options ","no-show-policy-url");
+                              "--list-options ","no-show-policy-urls");
            deprecated_warning(configname,configlineno,"--no-show-policy-url",
-                              "--verify-options ","no-show-policy-url");
-           opt.list_options&=~LIST_SHOW_POLICY;
-           opt.verify_options&=~VERIFY_SHOW_POLICY;
+                              "--verify-options ","no-show-policy-urls");
+           opt.list_options&=~LIST_SHOW_POLICY_URLS;
+           opt.verify_options&=~VERIFY_SHOW_POLICY_URLS;
            break;
          case oSigKeyserverURL: add_keyserver_url(pargs.r.ret_str,0); break;
          case oUseEmbeddedFilename: opt.use_embedded_filename = 1; break;
-         case oComment: add_to_strlist(&opt.comments,pargs.r.ret_str); break;
+         case oNoUseEmbeddedFilename: opt.use_embedded_filename = 0; break;
+         case oComment:
+           if(pargs.r.ret_str[0])
+             append_to_strlist(&opt.comments,pargs.r.ret_str);
+           break;
          case oDefaultComment:
            deprecated_warning(configname,configlineno,
                               "--default-comment","--no-comments","");
@@ -1667,8 +2169,8 @@ main( int argc, char **argv )
            free_strlist(opt.comments);
            opt.comments=NULL;
            break;
-         case oThrowKeyid: opt.throw_keyid = 1; break;
-         case oNoThrowKeyid: opt.throw_keyid = 0; break;
+         case oThrowKeyids: opt.throw_keyid = 1; break;
+         case oNoThrowKeyids: opt.throw_keyid = 0; break;
          case oShowPhotos:
            deprecated_warning(configname,configlineno,"--show-photos",
                               "--list-options ","show-photos");
@@ -1725,29 +2227,37 @@ main( int argc, char **argv )
          case oNoAskSigExpire: opt.ask_sig_expire = 0; break;
          case oAskCertExpire: opt.ask_cert_expire = 1; break;
          case oNoAskCertExpire: opt.ask_cert_expire = 0; break;
+         case oAskCertLevel: opt.ask_cert_level = 1; break;
+         case oNoAskCertLevel: opt.ask_cert_level = 0; break;
          case oUser: /* store the local users */
            add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
            break;
-         case oCompress: opt.compress = pargs.r.ret_int; break;
+         case oCompress:
+           /* this is the -z command line option */
+           opt.compress_level = opt.bz2_compress_level = pargs.r.ret_int;
+           break;
+         case oCompressLevel: opt.compress_level = pargs.r.ret_int; break;
+         case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break;
+         case oBZ2DecompressLowmem: opt.bz2_decompress_lowmem=1; break;
          case oPasswdFD:
             pwfd = iobuf_translate_file_handle (pargs.r.ret_int, 0);
             opt.use_agent = 0;
             break;
-#ifdef __riscos__
          case oPasswdFile:
-            pwfd = iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 0), 0);
+            pwfd = open_info_file (pargs.r.ret_str, 0);
             break;
-#endif /* __riscos__ */
          case oCommandFD:
             opt.command_fd = iobuf_translate_file_handle (pargs.r.ret_int, 0);
             break;
-#ifdef __riscos__
          case oCommandFile:
-            opt.command_fd = iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 0), 0);
+            opt.command_fd = open_info_file (pargs.r.ret_str, 0);
+            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;
-#endif /* __riscos__ */
-         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 oCompressAlgo:
            /* If it is all digits, stick a Z in front of it for
               later.  This is for backwards compatibility with
@@ -1764,22 +2274,24 @@ main( int argc, char **argv )
 
              if(*pt=='\0')
                {
-                 def_compress_string=m_alloc(strlen(pargs.r.ret_str)+2);
-                 strcpy(def_compress_string,"Z");
-                 strcat(def_compress_string,pargs.r.ret_str);
+                 compress_algo_string=m_alloc(strlen(pargs.r.ret_str)+2);
+                 strcpy(compress_algo_string,"Z");
+                 strcat(compress_algo_string,pargs.r.ret_str);
                }
              else
-               def_compress_string = m_strdup(pargs.r.ret_str);
+               compress_algo_string = m_strdup(pargs.r.ret_str);
            }
            break;
          case oCertDigestAlgo: cert_digest_string = m_strdup(pargs.r.ret_str); break;
          case oNoSecmemWarn: secmem_set_flags( secmem_get_flags() | 1 ); break;
+         case oRequireSecmem: require_secmem=1; break;
+         case oNoRequireSecmem: require_secmem=0; break;
          case oNoPermissionWarn: opt.no_perm_warn=1; break;
          case oNoMDCWarn: opt.no_mdc_warn=1; break;
-          case oCharset:
+          case oDisplayCharset:
            if( set_native_charset( pargs.r.ret_str ) )
-               log_error(_("%s is not a valid character set\n"),
-                                                   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;
@@ -1794,15 +2306,23 @@ main( int argc, char **argv )
 #endif /* __riscos__ */
             break;
          case oKeyServer:
-           opt.keyserver_uri=m_strdup(pargs.r.ret_str);
-           if(parse_keyserver_uri(pargs.r.ret_str,configname,configlineno))
-             log_error(_("could not parse keyserver URI\n"));
+           opt.keyserver=parse_keyserver_uri(pargs.r.ret_str,0,
+                                             configname,configlineno);
+           if(!opt.keyserver)
+             log_error(_("could not parse keyserver URL\n"));
            break;
          case oKeyServerOptions:
-           parse_keyserver_options(pargs.r.ret_str);
+           if(!parse_keyserver_options(pargs.r.ret_str))
+             {
+               if(configname)
+                 log_error(_("%s:%d: invalid keyserver options\n"),
+                           configname,configlineno);
+               else
+                 log_error(_("invalid keyserver options\n"));
+             }
            break;
          case oImportOptions:
-           if(!parse_import_options(pargs.r.ret_str,&opt.import_options))
+           if(!parse_import_options(pargs.r.ret_str,&opt.import_options,1))
              {
                if(configname)
                  log_error(_("%s:%d: invalid import options\n"),
@@ -1812,7 +2332,7 @@ main( int argc, char **argv )
              }
            break;
          case oExportOptions:
-           if(!parse_export_options(pargs.r.ret_str,&opt.export_options))
+           if(!parse_export_options(pargs.r.ret_str,&opt.export_options,1))
              {
                if(configname)
                  log_error(_("%s:%d: invalid export options\n"),
@@ -1822,46 +2342,32 @@ main( int argc, char **argv )
              }
            break;
          case oListOptions:
-           {
-             struct parse_options lopts[]=
-               {
-                 {"show-photos",LIST_SHOW_PHOTOS},
-                 {"show-policy-url",LIST_SHOW_POLICY},
-                 {"show-notation",LIST_SHOW_NOTATION},
-                 {"show-keyserver-url",LIST_SHOW_KEYSERVER},
-                 {"show-validity",LIST_SHOW_VALIDITY},
-                 {"show-long-keyid",LIST_SHOW_LONG_KEYID},
-                 {"show-unusable-uids",LIST_SHOW_UNUSABLE_UIDS},
-                 {"show-keyring",LIST_SHOW_KEYRING},
-                 {"show-sig-expire",LIST_SHOW_SIG_EXPIRE},
-                 {NULL,0}
-               };
-
-             if(!parse_options(pargs.r.ret_str,&opt.list_options,lopts))
-               {
-                 if(configname)
-                   log_error(_("%s:%d: invalid list options\n"),
-                             configname,configlineno);
-                 else
-                   log_error(_("invalid list options\n"));
-               }
-           }
+           if(!parse_list_options(pargs.r.ret_str))
+             {
+               if(configname)
+                 log_error(_("%s:%d: invalid list options\n"),
+                           configname,configlineno);
+               else
+                 log_error(_("invalid list options\n"));
+             }
            break;
          case oVerifyOptions:
            {
              struct parse_options vopts[]=
                {
-                 {"show-photos",VERIFY_SHOW_PHOTOS},
-                 {"show-policy-url",VERIFY_SHOW_POLICY},
-                 {"show-notation",VERIFY_SHOW_NOTATION},
-                 {"show-keyserver-url",VERIFY_SHOW_KEYSERVER},
-                 {"show-validity",VERIFY_SHOW_VALIDITY},
-                 {"show-long-keyid",VERIFY_SHOW_LONG_KEYID},
-                 {"show-unusable-uids",VERIFY_SHOW_UNUSABLE_UIDS},
-                 {NULL,0}
+                 {"show-photos",VERIFY_SHOW_PHOTOS,NULL},
+                 {"show-policy-urls",VERIFY_SHOW_POLICY_URLS,NULL},
+                 {"show-notations",VERIFY_SHOW_NOTATIONS,NULL},
+                 {"show-std-notations",VERIFY_SHOW_STD_NOTATIONS,NULL},
+                 {"show-standard-notations",VERIFY_SHOW_STD_NOTATIONS,NULL},
+                 {"show-user-notations",VERIFY_SHOW_USER_NOTATIONS,NULL},
+                 {"show-keyserver-urls",VERIFY_SHOW_KEYSERVER_URLS,NULL},
+                 {"show-uid-validity",VERIFY_SHOW_UID_VALIDITY,NULL},
+                 {"show-unusable-uids",VERIFY_SHOW_UNUSABLE_UIDS,NULL},
+                 {NULL,0,NULL}
                };
 
-             if(!parse_options(pargs.r.ret_str,&opt.verify_options,vopts))
+             if(!parse_options(pargs.r.ret_str,&opt.verify_options,vopts,1))
                {
                  if(configname)
                    log_error(_("%s:%d: invalid verify options\n"),
@@ -1873,7 +2379,7 @@ main( int argc, char **argv )
            break;
          case oTempDir: opt.temp_dir=pargs.r.ret_str; break;
          case oExecPath:
-           if(set_exec_path(pargs.r.ret_str,0))
+           if(set_exec_path(pargs.r.ret_str))
              log_error(_("unable to set exec-path to %s\n"),pargs.r.ret_str);
            else
              opt.exec_path_set=1;
@@ -1886,19 +2392,19 @@ main( int argc, char **argv )
          case oCertNotation: add_notation_data( pargs.r.ret_str, 1 ); break;
          case oShowNotation:
            deprecated_warning(configname,configlineno,"--show-notation",
-                              "--list-options ","show-notation");
+                              "--list-options ","show-notations");
            deprecated_warning(configname,configlineno,"--show-notation",
-                              "--verify-options ","show-notation");
-           opt.list_options|=LIST_SHOW_NOTATION;
-           opt.verify_options|=VERIFY_SHOW_NOTATION;
+                              "--verify-options ","show-notations");
+           opt.list_options|=LIST_SHOW_NOTATIONS;
+           opt.verify_options|=VERIFY_SHOW_NOTATIONS;
            break;
          case oNoShowNotation:
            deprecated_warning(configname,configlineno,"--no-show-notation",
-                              "--list-options ","no-show-notation");
+                              "--list-options ","no-show-notations");
            deprecated_warning(configname,configlineno,"--no-show-notation",
-                              "--verify-options ","no-show-notation");
-           opt.list_options&=~LIST_SHOW_NOTATION;
-           opt.verify_options&=~VERIFY_SHOW_NOTATION;
+                              "--verify-options ","no-show-notations");
+           opt.list_options&=~LIST_SHOW_NOTATIONS;
+           opt.verify_options&=~VERIFY_SHOW_NOTATIONS;
            break;
          case oUtf8Strings: utf8_strings = 1; break;
          case oNoUtf8Strings: utf8_strings = 0; break;
@@ -1917,11 +2423,10 @@ main( int argc, char **argv )
          case oNoLiteral: opt.no_literal = 1; break;
          case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break;
          case oHonorHttpProxy:
-                opt.keyserver_options.honor_http_proxy = 1;
+               add_to_strlist(&opt.keyserver_options.other,"http-proxy");
                deprecated_warning(configname,configlineno,
                                   "--honor-http-proxy",
-                                  "--keyserver-options ",
-                                  "honor-http-proxy");
+                                  "--keyserver-options ","http-proxy");
                break;
          case oFastListMode: opt.fast_list_mode = 1; break;
          case oFixedListMode: opt.fixed_list_mode = 1; break;
@@ -1933,8 +2438,11 @@ main( int argc, char **argv )
          case oNoRandomSeedFile: use_random_seed = 0; break;
          case oAutoKeyRetrieve:
          case oNoAutoKeyRetrieve:
-               opt.keyserver_options.auto_key_retrieve=
-                                            (pargs.r_opt==oAutoKeyRetrieve);
+               if(pargs.r_opt==oAutoKeyRetrieve)
+                 opt.keyserver_options.options|=KEYSERVER_AUTO_KEY_RETRIEVE;
+               else
+                 opt.keyserver_options.options&=~KEYSERVER_AUTO_KEY_RETRIEVE;
+
                deprecated_warning(configname,configlineno,
                           pargs.r_opt==oAutoKeyRetrieve?"--auto-key-retrieve":
                               "--no-auto-key-retrieve","--keyserver-options ",
@@ -1945,7 +2453,11 @@ main( int argc, char **argv )
          case oOverrideSessionKey:
                opt.override_session_key = pargs.r.ret_str;
                break;
-         case oMergeOnly: opt.merge_only = 1; break;
+         case oMergeOnly:
+               deprecated_warning(configname,configlineno,"--merge-only",
+                                  "--import-options ","merge-only");
+               opt.import_options|=IMPORT_MERGE_ONLY;
+           break;
           case oAllowSecretKeyImport: /* obsolete */ break;
          case oTryAllSecrets: opt.try_all_secrets = 1; break;
           case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
@@ -1974,6 +2486,7 @@ main( int argc, char **argv )
           case oLCctype: opt.lc_ctype = pargs.r.ret_str; break;
           case oLCmessages: opt.lc_messages = pargs.r.ret_str; break;
          case oGroup: add_group(pargs.r.ret_str); break;
+         case oUnGroup: rm_group(pargs.r.ret_str); break;
          case oNoGroups:
            while(opt.grouplist)
              {
@@ -1989,20 +2502,48 @@ main( int argc, char **argv )
           case oNoMangleDosFilenames: opt.mangle_dos_filenames = 0; break;
           case oEnableProgressFilter: opt.enable_progress_filter = 1; break;
          case oMultifile: multifile=1; break;
+         case oKeyidFormat:
+           if(ascii_strcasecmp(pargs.r.ret_str,"short")==0)
+             opt.keyid_format=KF_SHORT;
+           else if(ascii_strcasecmp(pargs.r.ret_str,"long")==0)
+             opt.keyid_format=KF_LONG;
+           else if(ascii_strcasecmp(pargs.r.ret_str,"0xshort")==0)
+             opt.keyid_format=KF_0xSHORT;
+           else if(ascii_strcasecmp(pargs.r.ret_str,"0xlong")==0)
+             opt.keyid_format=KF_0xLONG;
+           else
+             log_error("unknown keyid-format `%s'\n",pargs.r.ret_str);
+           break;
 
          default : pargs.err = configfp? 1:2; break;
          }
       }
 
+
     if( configfp ) {
        fclose( configfp );
        configfp = NULL;
-       m_free(configname); configname = NULL;
+        /* Remember the first config file name. */
+        if (!save_configname)
+          save_configname = configname;
+        else
+          m_free(configname);
+        configname = NULL;
        goto next_pass;
     }
     m_free( configname ); configname = NULL;
     if( log_get_errorcount(0) )
        g10_exit(2);
+
+    /* The command --gpgconf-list is pretty simple and may be called
+       directly after the option parsing. */
+    if (cmd == aGPGConfList)
+      {
+        gpgconf_list (save_configname);
+        g10_exit (0);
+      }
+    m_free (save_configname);
+
     if( nogreeting )
        greeting = 0;
 
@@ -2012,11 +2553,17 @@ main( int argc, char **argv )
        fprintf(stderr, "%s\n", strusage(15) );
     }
 #ifdef IS_DEVELOPMENT_VERSION
-    if( !opt.batch ) {
-       log_info("NOTE: THIS IS A DEVELOPMENT VERSION!\n");
-       log_info("It is only intended for test purposes and should NOT be\n");
-       log_info("used in a production environment or with production keys!\n");
-    }
+    if( !opt.batch )
+      {
+       const char *s;
+
+       if((s=strusage(20)))
+         log_info("%s\n",s);
+       if((s=strusage(21)))
+         log_info("%s\n",s);
+       if((s=strusage(22)))
+         log_info("%s\n",s);
+      }
 #endif
 
     if (opt.verbose > 2)
@@ -2044,6 +2591,14 @@ main( int argc, char **argv )
                        "--no-literal" );
     }
 
+#ifndef ENABLE_AGENT_SUPPORT   
+    if (opt.use_agent) {
+      log_info(_("NOTE: %s is not available in this version\n"),
+               "--use-agent");
+      opt.use_agent = 0;
+    }
+#endif /*!ENABLE_AGENT_SUPPORT*/
+
     if (opt.set_filesize)
        log_info(_("NOTE: %s is not for normal use!\n"), "--set-filesize");
     if( opt.batch )
@@ -2051,6 +2606,13 @@ main( int argc, char **argv )
 
     secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */
 
+    if(require_secmem && !got_secmem)
+      {
+       log_info(_("will not run with insecure memory due to %s\n"),
+                "--require-secmem");
+       g10_exit(2);
+      }
+
     set_debug();
 
     /* Do these after the switch(), so they can override settings. */
@@ -2121,7 +2683,9 @@ main( int argc, char **argv )
            opt.ask_cert_expire = 0;
            m_free(def_digest_string);
            def_digest_string = m_strdup("md5");
-           opt.def_compress_algo = 1;
+           m_free(s2k_digest_string);
+           s2k_digest_string = m_strdup("md5");
+           opt.compress_algo = COMPRESS_ALGO_ZIP;
          }
       }
     else if(PGP6)
@@ -2161,10 +2725,10 @@ main( int argc, char **argv )
        if( check_digest_algo(opt.def_digest_algo) )
            log_error(_("selected digest algorithm is invalid\n"));
     }
-    if( def_compress_string ) {
-       opt.def_compress_algo = string_to_compress_algo(def_compress_string);
-       m_free(def_compress_string); def_compress_string = NULL;
-       if( check_compress_algo(opt.def_compress_algo) )
+    if( compress_algo_string ) {
+       opt.compress_algo = string_to_compress_algo(compress_algo_string);
+       m_free(compress_algo_string); compress_algo_string = NULL;
+       if( check_compress_algo(opt.compress_algo) )
            log_error(_("selected compression algorithm is invalid\n"));
     }
     if( cert_digest_string ) {
@@ -2186,11 +2750,15 @@ main( int argc, char **argv )
            log_error(_("selected digest algorithm is invalid\n"));
     }
     if( opt.completes_needed < 1 )
-       log_error(_("completes-needed must be greater than 0\n"));
+      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"));
+      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"));
+      log_error(_("max-cert-depth must be in the range from 1 to 255\n"));
+    if(opt.def_cert_level<0 || opt.def_cert_level>3)
+      log_error(_("invalid default-cert-level; must be 0, 1, 2, or 3\n"));
+    if( opt.min_cert_level < 1 || opt.min_cert_level > 3 )
+      log_error(_("invalid min-cert-level; must be 1, 2, or 3\n"));
     switch( opt.s2k_mode ) {
       case 0:
        log_info(_("NOTE: simple S2K mode (0) is strongly discouraged\n"));
@@ -2200,16 +2768,14 @@ main( int argc, char **argv )
        log_error(_("invalid S2K mode; must be 0, 1 or 3\n"));
     }
 
-    if(opt.def_cert_check_level<0 || opt.def_cert_check_level>3)
-      log_error(_("invalid default-check-level; must be 0, 1, 2, or 3\n"));
-
     /* This isn't actually needed, but does serve to error out if the
        string is invalid. */
     if(opt.def_preference_list &&
        keygen_set_std_prefs(opt.def_preference_list,0))
       log_error(_("invalid default preferences\n"));
 
-    /* We provide defaults for the personal digest list */
+    /* We provide defaults for the personal digest list.  This is
+       SHA-1. */
     if(!pers_digest_list)
       pers_digest_list="h2";
 
@@ -2244,6 +2810,9 @@ main( int argc, char **argv )
          case aSym:
            cmdname="--symmetric";
            break;
+         case aEncrSym:
+           cmdname="--symmetric --encrypt";
+           break;
          case aStore:
            cmdname="--store";
            break;
@@ -2259,6 +2828,9 @@ main( int argc, char **argv )
     if( log_get_errorcount(0) )
        g10_exit(2);
 
+    if(opt.compress_level==0)
+      opt.compress_algo=COMPRESS_ALGO_NONE;
+
     /* Check our chosen algorithms against the list of legal
        algorithms. */
 
@@ -2285,10 +2857,10 @@ main( int argc, char **argv )
            badalg=digest_algo_to_string(opt.cert_digest_algo);
            badtype=PREFTYPE_HASH;
          }
-       else if(opt.def_compress_algo!=-1
-               && !algo_available(PREFTYPE_ZIP,opt.def_compress_algo,NULL))
+       else if(opt.compress_algo!=-1
+               && !algo_available(PREFTYPE_ZIP,opt.compress_algo,NULL))
          {
-           badalg=compress_algo_to_string(opt.def_compress_algo);
+           badalg=compress_algo_to_string(opt.compress_algo);
            badtype=PREFTYPE_ZIP;
          }
 
@@ -2297,18 +2869,18 @@ main( int argc, char **argv )
            switch(badtype)
              {
              case PREFTYPE_SYM:
-               log_info(_("you may not use cipher algorithm \"%s\" "
-                          "while in %s mode\n"),
+               log_info(_("you may not use cipher algorithm `%s'"
+                          " while in %s mode\n"),
                         badalg,compliance_option_string());
                break;
              case PREFTYPE_HASH:
-               log_info(_("you may not use digest algorithm \"%s\" "
-                          "while in %s mode\n"),
+               log_info(_("you may not use digest algorithm `%s'"
+                          " while in %s mode\n"),
                         badalg,compliance_option_string());
                break;
              case PREFTYPE_ZIP:
-               log_info(_("you may not use compression algorithm \"%s\" "
-                          "while in %s mode\n"),
+               log_info(_("you may not use compression algorithm `%s'"
+                          " while in %s mode\n"),
                         badalg,compliance_option_string());
                break;
              default:
@@ -2323,6 +2895,8 @@ main( int argc, char **argv )
     if( use_random_seed ) {
        char *p = make_filename(opt.homedir, "random_seed", NULL );
        set_random_seed_file(p);
+        if (!access (p, F_OK))
+          register_secured_file (p);
        m_free(p);
     }
 
@@ -2345,10 +2919,6 @@ main( int argc, char **argv )
        g10_opt_verbose = opt.verbose;
     }
 
-    /* Compression algorithm 0 means no compression at all */
-    if( opt.def_compress_algo == 0)
-        opt.compress = 0;
-
     /* kludge to let -sat generate a clear text signature */
     if( opt.textmode == 2 && !detached_sig && opt.armor && cmd == aSign )
        cmd = aClearsign;
@@ -2359,20 +2929,26 @@ main( int argc, char **argv )
     /* Add the keyrings, but not for some special commands and not in
        case of "-kvv userid keyring".  Also avoid adding the secret
        keyring for a couple of commands to avoid unneeded access in
-       case the secrings are stored on a floppy */
-    if( cmd != aDeArmor && cmd != aEnArmor
-       && !(cmd == aKMode && argc == 2 ) ) 
+       case the secrings are stored on a floppy.
+       
+       We always need to add the keyrings if we are running under
+       SELinux, this is so that the rings are added to the list of
+       secured files. */
+    if( ALWAYS_ADD_KEYRINGS 
+        || (cmd != aDeArmor && cmd != aEnArmor
+            && !(cmd == aKMode && argc == 2 )) ) 
       {
-        if (cmd != aCheckKeys && cmd != aListSigs && cmd != aListKeys
-            && cmd != aVerify && cmd != aSym)
+        if (ALWAYS_ADD_KEYRINGS
+            || (cmd != aCheckKeys && cmd != aListSigs && cmd != aListKeys
+                && cmd != aVerify && cmd != aSym))
           {
             if (!sec_nrings || default_keyring) /* add default secret rings */
-              keydb_add_resource ("secring" EXTSEP_S "gpg", 0, 1);
+              keydb_add_resource ("secring" EXTSEP_S "gpg", 4, 1);
             for (sl = sec_nrings; sl; sl = sl->next)
               keydb_add_resource ( sl->d, 0, 1 );
           }
        if( !nrings || default_keyring )  /* add default ring */
-           keydb_add_resource ("pubring" EXTSEP_S "gpg", 0, 0);
+           keydb_add_resource ("pubring" EXTSEP_S "gpg", 4, 0);
        for(sl = nrings; sl; sl = sl->next )
            keydb_add_resource ( sl->d, sl->flags, 0 );
       }
@@ -2402,7 +2978,8 @@ main( int argc, char **argv )
        log_error(_("failed to initialize the TrustDB: %s\n"), g10_errstr(rc));
 
 
-    switch (cmd) {
+    switch (cmd)
+      {
       case aStore: 
       case aSym:  
       case aSign: 
@@ -2414,22 +2991,23 @@ main( int argc, char **argv )
        break;
       default:
         break;
-    }
+      }
 
-    switch( cmd ) {
+    switch( cmd )
+      {
       case aStore: /* only store the file */
        if( argc > 1 )
            wrong_args(_("--store [filename]"));
        if( (rc = encode_store(fname)) )
-           log_error_f( print_fname_stdin(fname),
-                       "store failed: %s\n", g10_errstr(rc) );
+           log_error ("storing `%s' failed: %s\n",
+                       print_fname_stdin(fname),g10_errstr(rc) );
        break;
       case aSym: /* encrypt the given file only with the symmetric cipher */
        if( argc > 1 )
            wrong_args(_("--symmetric [filename]"));
        if( (rc = encode_symmetric(fname)) )
-           log_error_f(print_fname_stdin(fname),
-                       "symmetric encryption failed: %s\n",g10_errstr(rc) );
+            log_error (_("symmetric encryption of `%s' failed: %s\n"),
+                        print_fname_stdin(fname),g10_errstr(rc) );
        break;
 
       case aEncr: /* encrypt the given file */
@@ -2439,12 +3017,33 @@ main( int argc, char **argv )
          {
            if( argc > 1 )
              wrong_args(_("--encrypt [filename]"));
-           if( (rc = encode_crypt(fname,remusr)) )
+           if( (rc = encode_crypt(fname,remusr,0)) )
+             log_error("%s: encryption failed: %s\n",
+                       print_fname_stdin(fname), g10_errstr(rc) );
+         }
+       break;
+
+      case aEncrSym:
+       /* This works with PGP 8 in the sense that it acts just like a
+          symmetric message.  It doesn't work at all with 2 or 6.  It
+          might work with 7, but alas, I don't have a copy to test
+          with right now. */
+       if( argc > 1 )
+         wrong_args(_("--symmetric --encrypt [filename]"));
+       else if(opt.s2k_mode==0)
+         log_error(_("you cannot use --symmetric --encrypt"
+                     " with --s2k-mode 0\n"));
+       else if(PGP2 || PGP6 || PGP7 || RFC1991)
+         log_error(_("you cannot use --symmetric --encrypt"
+                     " while in %s mode\n"),compliance_option_string());
+       else
+         {
+           if( (rc = encode_crypt(fname,remusr,1)) )
              log_error("%s: encryption failed: %s\n",
                        print_fname_stdin(fname), g10_errstr(rc) );
          }
        break;
-          
+
       case aSign: /* sign the given file */
        sl = NULL;
        if( detached_sig ) { /* sign all files */
@@ -2474,10 +3073,36 @@ main( int argc, char **argv )
        else
            sl = NULL;
        if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) )
-           log_error("%s: sign+encrypt failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
+           log_error("%s: sign+encrypt failed: %s\n",
+                     print_fname_stdin(fname), g10_errstr(rc) );
        free_strlist(sl);
        break;
 
+      case aSignEncrSym: /* sign and encrypt the given file */
+       if( argc > 1 )
+           wrong_args(_("--symmetric --sign --encrypt [filename]"));
+       else if(opt.s2k_mode==0)
+         log_error(_("you cannot use --symmetric --sign --encrypt"
+                     " with --s2k-mode 0\n"));
+       else if(PGP2 || PGP6 || PGP7 || RFC1991)
+         log_error(_("you cannot use --symmetric --sign --encrypt"
+                     " while in %s mode\n"),compliance_option_string());
+       else
+         {
+           if( argc )
+             {
+               sl = m_alloc_clear( sizeof *sl + strlen(fname));
+               strcpy(sl->d, fname);
+             }
+           else
+             sl = NULL;
+           if( (rc = sign_file(sl, detached_sig, locusr, 2, remusr, NULL)) )
+             log_error("%s: symmetric+sign+encrypt failed: %s\n",
+                       print_fname_stdin(fname), g10_errstr(rc) );
+           free_strlist(sl);
+         }
+       break;
+
       case aSignSym: /* sign and conventionally encrypt the given file */
        if (argc > 1)
            wrong_args(_("--sign --symmetric [filename]"));
@@ -2520,37 +3145,30 @@ main( int argc, char **argv )
          }
        break;
             
-      case aSignKey: /* sign the key given as argument */
+      case aSignKey:
        if( argc != 1 )
-           wrong_args(_("--sign-key user-id"));
-       username = make_username( fname );
-       keyedit_menu(fname, locusr, NULL, 1 );
-       m_free(username);
-       break;
-
+         wrong_args(_("--sign-key user-id"));
+       /* fall through */
       case aLSignKey:
        if( argc != 1 )
-           wrong_args(_("--lsign-key user-id"));
-       username = make_username( fname );
-       keyedit_menu(fname, locusr, NULL, 2 );
-       m_free(username);
-       break;
+         wrong_args(_("--lsign-key user-id"));
+       /* fall through */
 
-      case aNRSignKey:
-       if( argc != 1 )
-           wrong_args(_("--nrsign-key user-id"));
-       username = make_username( fname );
-       keyedit_menu(fname, locusr, NULL, 3 );
-        m_free(username);
-        break;
+       sl=NULL;
 
-      case aNRLSignKey:
-       if( argc != 1 )
-           wrong_args(_("--nrlsign-key user-id"));
+       if(cmd==aSignKey)
+         append_to_strlist(&sl,"sign");
+       else if(cmd==aLSignKey)
+         append_to_strlist(&sl,"lsign");
+       else
+         BUG();
+
+       append_to_strlist( &sl, "save" );
        username = make_username( fname );
-       keyedit_menu(fname, locusr, NULL, 4 );
-        m_free(username);
-        break;
+       keyedit_menu(fname, locusr, sl, 0, 0 );
+       m_free(username);
+       free_strlist(sl);
+       break;
 
       case aEditKey: /* Edit a key signature */
        if( !argc )
@@ -2560,11 +3178,11 @@ main( int argc, char **argv )
            sl = NULL;
            for( argc--, argv++ ; argc; argc--, argv++ )
                append_to_strlist( &sl, *argv );
-           keyedit_menu( username, locusr, sl, 0 );
+           keyedit_menu( username, locusr, sl, 0, 1 );
            free_strlist(sl);
        }
        else
-           keyedit_menu(username, locusr, NULL, 0 );
+           keyedit_menu(username, locusr, NULL, 0, 1 );
        m_free(username);
        break;
 
@@ -2610,7 +3228,7 @@ main( int argc, char **argv )
        }
        else if( argc == 2 ) { /* -kv userid keyring */
            if( access( argv[1], R_OK ) ) {
-               log_error(_("can't open %s: %s\n"),
+               log_error(_("can't open `%s': %s\n"),
                               print_fname_stdin(argv[1]), strerror(errno));
            }
            else {
@@ -2632,23 +3250,22 @@ main( int argc, char **argv )
        if( opt.batch ) {
            if( argc > 1 )
                wrong_args("--gen-key [parameterfile]");
-           generate_keypair( argc? *argv : NULL, NULL );
+           generate_keypair( argc? *argv : NULL, NULL, NULL );
        }
        else {
            if( argc )
                wrong_args("--gen-key");
-           generate_keypair(NULL, NULL);
+           generate_keypair(NULL, NULL, NULL);
        }
        break;
 
       case aFastImport:
-        opt.import_options |= IMPORT_FAST_IMPORT;
+        opt.import_options |= IMPORT_FAST;
       case aImport:
        import_keys( argc? argv:NULL, argc, NULL, opt.import_options );
        break;
 
       case aExport:
-      case aExportAll:
       case aSendKeys:
       case aRecvKeys:
        sl = NULL;
@@ -2676,7 +3293,6 @@ main( int argc, char **argv )
        sl = NULL;
        for( ; argc; argc--, argv++ )
          append_to_strlist2( &sl, *argv, utf8_strings );
-
        rc=keyserver_search( sl );
        if(rc)
          log_error(_("keyserver search failed: %s\n"),g10_errstr(rc));
@@ -2904,14 +3520,14 @@ main( int argc, char **argv )
       case aRebuildKeydbCaches:
         if (argc)
             wrong_args ("--rebuild-keydb-caches");
-        keydb_rebuild_caches ();
+        keydb_rebuild_caches (1);
         break;
 
 #ifdef ENABLE_CARD_SUPPORT
       case aCardStatus:
         if (argc)
             wrong_args ("--card-status");
-        card_status (stdout);
+        card_status (stdout, NULL, 0);
         break;
 
       case aCardEdit:
@@ -2928,14 +3544,21 @@ main( int argc, char **argv )
 
       case aChangePIN:
         if (!argc)
-            change_pin (0);
+            change_pin (0,1);
         else if (argc == 1)
-            change_pin ( atoi (*argv));
+            change_pin (atoi (*argv),1);
         else
         wrong_args ("--change-pin [no]");
         break;
 #endif /* ENABLE_CARD_SUPPORT*/
 
+      case aListConfig:
+       {
+         char *str=collapse_args(argc,argv);
+         list_config(str);
+         m_free(str);
+       }
+       break;
 
       case aListPackets:
        opt.list_packets=2;
@@ -2947,7 +3570,14 @@ main( int argc, char **argv )
                && isatty( fileno(stdout) ) && isatty( fileno(stderr) ) )
            log_info(_("Go ahead and type your message ...\n"));
 
-       if( !(a = iobuf_open(fname)) )
+       a = iobuf_open(fname);
+        if (a && is_secured_file (iobuf_get_fd (a)))
+          {
+            iobuf_close (a);
+            a = NULL;
+            errno = EPERM;
+          }
+       if( !a )
            log_error(_("can't open `%s'\n"), print_fname_stdin(fname));
        else {
 
@@ -2967,7 +3597,7 @@ main( int argc, char **argv )
            iobuf_close(a);
        }
        break;
-    }
+      }
 
     /* cleanup */
     FREE_STRLIST(remusr);
@@ -3120,6 +3750,12 @@ print_mds( const char *fname, int algo )
     }
     else {
        fp = fopen( fname, "rb" );
+        if (fp && is_secured_file (fileno (fp)))
+          {
+            fclose (fp);
+            fp = NULL;
+            errno = EPERM;
+          }
     }
     if( !fp ) {
        log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) );
@@ -3230,8 +3866,7 @@ add_notation_data( const char *string, int which )
 
     if(!saw_at && !opt.expert)
       {
-       log_error(
-               _("a user notation name must contain the '@' character\n"));
+       log_error(_("a user notation name must contain the '@' character\n"));
        return;
       }
 
@@ -3241,8 +3876,8 @@ add_notation_data( const char *string, int which )
        if ((*s & 0x80))
           highbit = 1;
        else if (iscntrl(*s)) {
-           log_error(_("a notation value must not use "
-                       "any control characters\n") );
+           log_error(_("a notation value must not use"
+                       " any control characters\n") );
            return;
        }
     }
@@ -3259,7 +3894,7 @@ add_notation_data( const char *string, int which )
 static void
 add_policy_url( const char *string, int which )
 {
-  int i,critical=0;
+  unsigned int i,critical=0;
   STRLIST sl;
 
   if(*string=='!')
@@ -3292,7 +3927,7 @@ add_policy_url( const char *string, int which )
 static void
 add_keyserver_url( const char *string, int which )
 {
-  int i,critical=0;
+  unsigned int i,critical=0;
   STRLIST sl;
 
   if(*string=='!')
@@ -3310,8 +3945,7 @@ add_keyserver_url( const char *string, int which )
       if(which)
        BUG();
       else
-       log_error(_("the given signature preferred"
-                   " keyserver URL is invalid\n"));
+       log_error(_("the given preferred keyserver URL is invalid\n"));
     }
 
   if(which)