* keygen.c (generate_keypair): Create an AUTHKEYTYPE entry for cards.
[gnupg.git] / g10 / g10.c
index 70c609c..b7ad9d7 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -1,5 +1,5 @@
 /* g10.c - The GnuPG utility (main for gpg)
- * Copyright (C) 1998,1999,2000,2001,2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
+#include <assert.h>
 #ifdef HAVE_DOSISH_SYSTEM
-  #include <fcntl.h> /* for setmode() */
+#include <fcntl.h> /* for setmode() */
 #endif
 #ifdef HAVE_STAT
 #include <sys/stat.h> /* for stat() */
 #endif
 
 #define INCLUDED_BY_MAIN_MODULE 1
+#include "gpg.h"
 #include "packet.h"
 #include "iobuf.h"
 #include "memory.h"
@@ -47,7 +49,6 @@
 #include "ttyio.h"
 #include "i18n.h"
 #include "status.h"
-#include "g10defs.h"
 #include "keyserver-internal.h"
 #include "exec.h"
 
@@ -64,6 +65,7 @@ enum cmd_and_opt_values { aNull = 0,
     oOutput      = 'o',
     oQuiet       = 'q',
     oRecipient   = 'r',
+    oHiddenRecipient = 'R',
     aSign        = 's',
     oTextmodeShort= 't',
     oUser        = 'u',
@@ -118,6 +120,7 @@ enum cmd_and_opt_values { aNull = 0,
     aListTrustDB,
     aListTrustPath,
     aExportOwnerTrust,
+    aListOwnerTrust,
     aImportOwnerTrust,
     aDeArmor,
     aEnArmor,
@@ -125,8 +128,10 @@ enum cmd_and_opt_values { aNull = 0,
     aPipeMode,
     aRebuildKeydbCaches,
     aRefreshKeys,
+    aChangePIN,
 
     oTextmode,
+    oNoTextmode,
     oExpert,
     oNoExpert,
     oAskSigExpire,
@@ -139,6 +144,7 @@ enum cmd_and_opt_values { aNull = 0,
     oAnswerNo,
     oDefCertCheckLevel,
     oKeyring,
+    oPrimaryKeyring,
     oSecretKeyring,
     oShowKeyring,
     oDefaultKey,
@@ -158,20 +164,19 @@ enum cmd_and_opt_values { aNull = 0,
 #endif /* __riscos__ */
     oSKComments,
     oNoSKComments,
-    oNoVersion,
     oEmitVersion,
+    oNoEmitVersion,
     oCompletesNeeded,
     oMarginalsNeeded,
     oMaxCertDepth,
     oLoadExtension,
+    oGnuPG,
     oRFC1991,
     oOpenPGP,
     oPGP2,
-    oNoPGP2,
     oPGP6,
-    oNoPGP6,
     oPGP7,
-    oNoPGP7,
+    oPGP8,
     oCipherAlgo,
     oDigestAlgo,
     oCertDigestAlgo,
@@ -203,6 +208,8 @@ enum cmd_and_opt_values { aNull = 0,
     oCompressKeys,
     oCompressSigs,
     oAlwaysTrust,
+    oTrustModel,
+    oForceOwnertrust,
     oEmuChecksumBug,
     oRunAsShmCP,
     oSetFilename,
@@ -217,6 +224,7 @@ enum cmd_and_opt_values { aNull = 0,
     oComment,
     oDefaultComment,
     oThrowKeyid,
+    oNoThrowKeyid,
     oShowPhotos,
     oNoShowPhotos,
     oPhotoViewer,
@@ -243,9 +251,12 @@ enum cmd_and_opt_values { aNull = 0,
     oKeyServerOptions,
     oImportOptions,
     oExportOptions,
+    oListOptions,
+    oVerifyOptions,
     oTempDir,
     oExecPath,
     oEncryptTo,
+    oHiddenEncryptTo,
     oNoEncryptTo,
     oLoggerFD,
 #ifdef __riscos__
@@ -292,14 +303,19 @@ enum cmd_and_opt_values { aNull = 0,
     oPersonalCipherPreferences,
     oPersonalDigestPreferences,
     oPersonalCompressPreferences,
-    oEmu3DESS2KBug,  /* will be removed in 1.1 */
     oEmuMDEncodeBug,
+    oAgentProgram,
     oDisplay,
     oTTYname,
     oTTYtype,
     oLCctype,
     oLCmessages,
     oGroup,
+    oStrict,
+    oNoStrict,
+    oMangleDosFilenames,
+    oNoMangleDosFilenames,
+    oEnableProgressFilter,                          
 aTest };
 
 
@@ -347,11 +363,13 @@ static ARGPARSE_OPTS opts[] = {
     { aExportSecretSub, "export-secret-subkeys" , 256, "@" },
     { aImport, "import",      256     , N_("import/merge keys")},
     { aFastImport, "fast-import",  256 , "@"},
+    { aChangePIN,  "change-pin", 256, N_("change a card's PIN")},
+
     { aListPackets, "list-packets",256,N_("list only the sequence of packets")},
     { aExportOwnerTrust,
              "export-ownertrust", 256, N_("export the ownertrust values")},
     { aImportOwnerTrust,
-             "import-ownertrust", 256 , N_("import ownertrust values")},
+             "import-ownertrust", 256, N_("import ownertrust values")},
     { aUpdateTrustDB,
              "update-trustdb",0 , N_("update the trust database")},
     { aCheckTrustDB,
@@ -370,6 +388,7 @@ static ARGPARSE_OPTS opts[] = {
     { oArmor, "armor",     0, N_("create ascii armored output")},
     { oArmor, "armour",     0, "@" },
     { oRecipient, "recipient", 2, N_("|NAME|encrypt for NAME")},
+    { oHiddenRecipient, "hidden-recipient", 2, "@" },
     { oRecipient, "remote-user", 2, "@"},  /* old option name */
     { oDefRecipient, "default-recipient" ,2,
                                  N_("|NAME|use NAME as default recipient")},
@@ -379,11 +398,13 @@ static ARGPARSE_OPTS opts[] = {
     { oTempDir, "temp-directory", 2, "@" },
     { oExecPath, "exec-path", 2, "@" },
     { oEncryptTo, "encrypt-to", 2, "@" },
+    { 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)") },
     { oTextmodeShort, NULL,   0, "@"},
     { oTextmode, "textmode",  0, N_("use canonical text mode")},
+    { oNoTextmode, "no-textmode",  0, "@"},
     { oExpert, "expert",   0, "@"},
     { oNoExpert, "no-expert",   0, "@"},
     { oAskSigExpire, "ask-sig-expire",   0, "@"},
@@ -403,7 +424,7 @@ static ARGPARSE_OPTS opts[] = {
     { oDisableMDC, "disable-mdc", 0, N_("never use a MDC for encryption") },
     { oNoDisableMDC, "no-disable-mdc", 0, "@" },
     { oDryRun, "dry-run",   0, N_("do not make any changes") },
-  /*{ oInteractive, "interactive", 0, N_("prompt before overwriting") }, */
+    { oInteractive, "interactive", 0, N_("prompt before overwriting") },
     { oUseAgent, "use-agent",0, N_("use the gpg-agent")},
     { oNoUseAgent, "no-use-agent",0, "@"},
     { oGpgAgentInfo, "gpg-agent-info",2, "@"},
@@ -411,6 +432,7 @@ static ARGPARSE_OPTS opts[] = {
     { oAnswerYes, "yes",       0, N_("assume yes on most questions")},
     { oAnswerNo,  "no",        0, N_("assume no on most questions")},
     { oKeyring, "keyring"   ,2, N_("add this keyring to the list of keyrings")},
+    { oPrimaryKeyring, "primary-keyring",2, "@" },
     { oSecretKeyring, "secret-keyring" ,2, N_("add this secret keyring to the list")},
     { oShowKeyring, "show-keyring", 0, N_("show which keyring a listed key is on")},
     { oDefaultKey, "default-key" ,2, N_("|NAME|use NAME as default secret key")},
@@ -418,6 +440,7 @@ static ARGPARSE_OPTS opts[] = {
     { oKeyServerOptions, "keyserver-options",2,"@"},
     { oImportOptions, "import-options",2,"@"},
     { oExportOptions, "export-options",2,"@"},
+    { oListOptions, "list-options",2,"@"},
     { oCharset, "charset"   , 2, N_("|NAME|set terminal charset to NAME") },
     { oOptions, "options"   , 2, N_("read options from file")},
 
@@ -439,14 +462,17 @@ static ARGPARSE_OPTS opts[] = {
     { oMaxCertDepth,   "max-cert-depth", 1, "@" },
     { oTrustedKey, "trusted-key", 2, N_("|KEYID|ultimately trust this key")},
     { oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")},
+    { oGnuPG, "gnupg",   0, "@"},
+    { oGnuPG, "no-pgp2", 0, "@"},
+    { oGnuPG, "no-pgp6", 0, "@"},
+    { oGnuPG, "no-pgp7", 0, "@"},
+    { oGnuPG, "no-pgp8", 0, "@"},
     { oRFC1991, "rfc1991",   0, N_("emulate the mode described in RFC1991")},
     { oOpenPGP, "openpgp", 0, N_("set all packet, cipher and digest options to OpenPGP behavior")},
     { oPGP2, "pgp2", 0, N_("set all packet, cipher and digest options to PGP 2.x behavior")},
-    { oNoPGP2, "no-pgp2", 0, "@"},
     { oPGP6, "pgp6", 0, "@"},
-    { oNoPGP6, "no-pgp6", 0, "@"},
     { oPGP7, "pgp7", 0, "@"},
-    { oNoPGP7, "no-pgp7", 0, "@"},
+    { oPGP8, "pgp8", 0, "@"},
     { oS2KMode, "s2k-mode",  1, N_("|N|use passphrase mode N")},
     { oS2KDigest, "s2k-digest-algo",2,
                N_("|NAME|use message digest algorithm NAME for passphrases")},
@@ -456,11 +482,12 @@ static ARGPARSE_OPTS opts[] = {
     { oCipherAlgo, "cipher-algo", 2 , N_("|NAME|use cipher algorithm NAME")},
     { oDigestAlgo, "digest-algo", 2 , N_("|NAME|use message digest algorithm NAME")},
     { oCertDigestAlgo, "cert-digest-algo", 2 , "@" },
-    { oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")},
+    { oCompressAlgo,"compress-algo",2,N_("|NAME|use compression algorithm NAME")},
     { oThrowKeyid, "throw-keyid", 0, N_("throw keyid field of encrypted packets")},
-    { oShowPhotos,   "show-photos", 0, N_("Show Photo IDs")},
-    { oNoShowPhotos, "no-show-photos", 0, N_("Don't show Photo IDs")},
-    { oPhotoViewer,  "photo-viewer", 2, N_("Set command line to view Photo IDs")},
+    { oNoThrowKeyid, "no-throw-keyid", 0, "@" },
+    { oShowPhotos,   "show-photos", 0, "@" },
+    { oNoShowPhotos, "no-show-photos", 0, "@" },
+    { oPhotoViewer,  "photo-viewer", 2, "@" },
     { oNotation,   "notation-data", 2, "@" },
     { oSigNotation,   "sig-notation", 2, "@" },
     { oCertNotation,  "cert-notation", 2, "@" },
@@ -477,10 +504,12 @@ static ARGPARSE_OPTS opts[] = {
     " --fingerprint [names]      show fingerprints\n"  ) },
 
   /* hidden options */
-    { aExportOwnerTrust, "list-ownertrust",0 , "@"},  /* alias */
+    { aListOwnerTrust, "list-ownertrust", 256, "@"}, /* deprecated */
+    { oCompressAlgo, "compression-algo", 1, "@"}, /* alias */
     { aPrintMDs, "print-mds" , 256, "@"}, /* old */
     { aListTrustDB, "list-trustdb",0 , "@"},
-    { aListTrustPath, "list-trust-path",0, "@"},
+    /* Not yet used */
+    /* { aListTrustPath, "list-trust-path",0, "@"}, */
     { aPipeMode,  "pipemode", 0, "@" },
     { oKOption, NULL,   0, "@"},
     { oPasswdFD, "passphrase-fd",1, "@" },
@@ -514,6 +543,8 @@ static ARGPARSE_OPTS opts[] = {
     { oCompressSigs, "compress-sigs",0, "@"},
     { oDefCertCheckLevel, "default-cert-check-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, "@" },
@@ -528,8 +559,9 @@ static ARGPARSE_OPTS opts[] = {
     { oNoShowNotation, "no-show-notation", 0, "@" },
     { oComment, "comment", 2, "@" },
     { oDefaultComment, "default-comment", 0, "@" },
-    { oNoVersion, "no-version", 0, "@"},
     { oEmitVersion, "emit-version", 0, "@"},
+    { oNoEmitVersion, "no-emit-version", 0, "@"},
+    { oNoEmitVersion, "no-version", 0, "@"}, /* alias */
     { oNotDashEscaped, "not-dash-escaped", 0, "@" },
     { oEscapeFrom, "escape-from-lines", 0, "@" },
     { oNoEscapeFrom, "no-escape-from-lines", 0, "@" },
@@ -581,14 +613,19 @@ static ARGPARSE_OPTS opts[] = {
     { oPersonalCipherPreferences,  "personal-cipher-preferences", 2, "@"},
     { oPersonalDigestPreferences,  "personal-digest-preferences", 2, "@"},
     { oPersonalCompressPreferences,  "personal-compress-preferences", 2, "@"},
-    { oEmu3DESS2KBug,  "emulate-3des-s2k-bug", 0, "@"},
     { oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
+    { oAgentProgram, "agent-program", 2 , "@" },
     { oDisplay,    "display",     2, "@" },
     { oTTYname,    "ttyname",     2, "@" },
     { oTTYtype,    "ttytype",     2, "@" },
     { oLCctype,    "lc-ctype",    2, "@" },
     { oLCmessages, "lc-messages", 2, "@" },
     { oGroup,      "group",       2, "@" },
+    { oStrict,     "strict",      0, "@" },
+    { oNoStrict,   "no-strict",   0, "@" },
+    { oMangleDosFilenames, "mangle-dos-filenames", 0, "@" },
+    { oNoMangleDosFilenames, "no-mangle-dos-filenames", 0, "@" },
+    { oEnableProgressFilter, "enable-progress-filter", 0, "@" },
 {0} };
 
 
@@ -602,17 +639,24 @@ static char *build_list( const char *text, char letter,
                         const char *(*mapf)(int), int (*chkf)(int) );
 static void set_cmd( enum cmd_and_opt_values *ret_cmd,
                        enum cmd_and_opt_values new_cmd );
-static void print_hex( byte *p, size_t n );
 static void print_mds( const char *fname, int algo );
 static void add_notation_data( const char *string, int which );
 static void add_policy_url( const char *string, int which );
+static void emergency_cleanup (void);
 
 #ifdef __riscos__
 RISCOS_GLOBAL_STATICS("GnuPG Heap")
 #endif /* __riscos__ */
 
-const char *
-strusage( int level )
+static int
+pk_test_algo (int algo)
+{
+  return openpgp_pk_test_algo (algo, 0);
+}
+
+
+static const char *
+my_strusage( int level )
 {
   static char *digests, *pubkeys, *ciphers, *zips;
     const char *p;
@@ -643,30 +687,30 @@ strusage( int level )
       case 33: p = _("\nSupported algorithms:\n"); break;
       case 34:
        if( !pubkeys )
-           pubkeys = build_list("Pubkey: ", 0, pubkey_algo_to_string,
-                                                       check_pubkey_algo );
+           pubkeys = build_list(_("Pubkey: "), 0, gcry_pk_algo_name,
+                                 pk_test_algo );
        p = pubkeys;
        break;
       case 35:
        if( !ciphers )
-           ciphers = build_list("Cipher: ", 'S', cipher_algo_to_string,
-                                                       check_cipher_algo );
+           ciphers = build_list(_("Cipher: "), 'S', gcry_cipher_algo_name,
+                                 openpgp_cipher_test_algo );
        p = ciphers;
        break;
       case 36:
        if( !digests )
-           digests = build_list("Hash: ", 'H', digest_algo_to_string,
-                                                       check_digest_algo );
+           digests = build_list(_("Hash: "), 'H', gcry_md_algo_name,
+                                       openpgp_md_test_algo );
        p = digests;
        break;
       case 37:
        if( !zips )
-           zips = build_list("Compress: ",'Z',compress_algo_to_string,
+           zips = build_list(_("Compression: "),'Z',compress_algo_to_string,
                                                        check_compress_algo);
        p = zips;
        break;
 
-      default: p = default_strusage(level);
+      default: p = NULL;
     }
     return p;
 }
@@ -682,12 +726,12 @@ build_list( const char *text, char letter,
     char *list, *p, *line=NULL;
 
     if( maybe_setuid )
-       secmem_init( 0 );    /* drop setuid */
+        gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* drop setuid */
 
     for(i=0; i <= 110; i++ )
        if( !chkf(i) && (s=mapf(i)) )
            n += strlen(s) + 7 + 2;
-    list = m_alloc( 21 + n ); *list = 0;
+    list = xmalloc ( 21 + n ); *list = 0;
     for(p=NULL, i=0; i <= 110; i++ ) {
        if( !chkf(i) && (s=mapf(i)) ) {
            if( !p ) {
@@ -700,7 +744,7 @@ build_list( const char *text, char letter,
            if(strlen(line)>60) {
              int spaces=strlen(text);
 
-             list=m_realloc(list,n+spaces+1);
+             list = xrealloc(list,n+spaces+1);
              /* realloc could move the block, so find the end again */
              p=list;
              while(*p)
@@ -730,15 +774,15 @@ build_list( const char *text, char letter,
 static void
 i18n_init(void)
 {
-  #ifdef USE_SIMPLE_GETTEXT
+#ifdef USE_SIMPLE_GETTEXT
     set_gettext_file( PACKAGE );
-  #else
-  #ifdef ENABLE_NLS
+#else
+#ifdef ENABLE_NLS
     setlocale( LC_ALL, "" );
-    bindtextdomain( PACKAGE, G10_LOCALEDIR );
+    bindtextdomain( PACKAGE, LOCALEDIR );
     textdomain( PACKAGE );
-  #endif
-  #endif
+#endif
+#endif
 }
 
 static void
@@ -751,32 +795,69 @@ wrong_args( const char *text)
 }
 
 
+static void
+log_set_strict (int yesno)
+{
+  /* FIXME-XXX*/
+}
+
 static char *
 make_username( const char *string )
 {
     char *p;
     if( utf8_strings )
-       p = m_strdup(string);
+       p = xstrdup (string);
     else
        p = native_to_utf8( string );
     return p;
 }
 
 
+/*
+ * same as add_to_strlist() but if is_utf8 is *not* set a conversion
+ * to UTF8 is done  
+ */
+static STRLIST
+add_to_strlist2 ( STRLIST *list, const char *string, int is_utf8)
+{
+  STRLIST sl;
+  
+  if (is_utf8)
+    sl = add_to_strlist( list, string );
+  else 
+    {
+      char *p = native_to_utf8( string );
+      sl = add_to_strlist( list, p );
+      xfree( p );
+    }
+  return sl;
+}
+
+
 static void
 set_debug(void)
 {
-    if( opt.debug & DBG_MEMORY_VALUE )
-       memory_debug_mode = 1;
-    if( opt.debug & DBG_MEMSTAT_VALUE )
-       memory_stat_debug_mode = 1;
-    if( opt.debug & DBG_MPI_VALUE )
-       mpi_debug_mode = 1;
-    if( opt.debug & DBG_CIPHER_VALUE )
-       g10c_debug_mode = 1;
-    if( opt.debug & DBG_IOBUF_VALUE )
-       iobuf_debug_mode = 1;
+  if (opt.debug & DBG_MEMORY_VALUE )
+    memory_debug_mode = 1;
+  if (opt.debug & DBG_MEMSTAT_VALUE )
+    memory_stat_debug_mode = 1;
+  if (opt.debug & DBG_MPI_VALUE)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
+  if (opt.debug & DBG_CIPHER_VALUE )
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
+  if (opt.debug & DBG_IOBUF_VALUE )
+    iobuf_debug_mode = 1;
+}
 
+
+/* We need the home directory also in some other directories, so make
+   sure that both variables are always in sync. */
+static void
+set_homedir (char *dir)
+{
+  if (!dir)
+    dir = "";
+  g10_opt_homedir = opt.homedir = dir;
 }
 
 
@@ -816,18 +897,23 @@ static void add_group(char *string)
   STRLIST values=NULL;
 
   /* Break off the group name */
-  name=strsep(&string," ");
+  name=strsep(&string,"=");
   if(string==NULL)
     {
-      log_error(_("no values for group \"%s\"\n"),name);
+      log_error(_("no = sign found in group definition \"%s\"\n"),name);
       return;
     }
 
+  trim_trailing_ws(name,strlen(name));
+
   /* Break apart the values */
-  while((value=strsep(&string," ")) && *value!='\0')
-    add_to_strlist2(&values,value,utf8_strings);
+  while ((value= strsep(&string," \t")))
+    {
+      if (*value)
+        add_to_strlist2 (&values,value,utf8_strings);
+    }
 
-  item=m_alloc(sizeof(struct groupitem));
+  item=xmalloc (sizeof(struct groupitem));
   item->name=name;
   item->values=values;
   item->next=opt.grouplist;
@@ -852,7 +938,7 @@ check_permissions(const char *path,int item)
 {
 #if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
   static int homedir_cache=-1;
-  char *tmppath,*isa,*dir;
+  char *tmppath,*dir;
   struct stat statbuf,dirbuf;
   int homedir=0,ret=0,checkonly=0;
   int perm=0,own=0,enc_dir_perm=0,enc_dir_own=0;
@@ -860,6 +946,8 @@ check_permissions(const char *path,int item)
   if(opt.no_perm_warn)
     return 0;
 
+  assert(item==0 || item==1 || item==2);
+
   /* extensions may attach a path */
   if(item==2 && path[0]!=DIRSEP_C)
     {
@@ -869,15 +957,15 @@ check_permissions(const char *path,int item)
        tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
     }
   else
-    tmppath=m_strdup(path);
+    tmppath=xstrdup (path);
 
   /* If the item is located in the homedir, but isn't the homedir,
      don't continue if we already checked the homedir itself.  This is
      to avoid user confusion with an extra options file warning which
      could be rectified if the homedir itself had proper
      permissions. */
-  if(item!=0 && homedir_cache>-1 &&
-     ascii_memcasecmp(opt.homedir,tmppath,strlen(opt.homedir))==0)
+  if(item!=0 && homedir_cache>-1
+     && ascii_strncasecmp(opt.homedir,tmppath,strlen(opt.homedir))==0)
     {
       ret=homedir_cache;
       goto end;
@@ -902,15 +990,13 @@ check_permissions(const char *path,int item)
       goto end;
     }
 
-  m_free(dir);
+  xfree (dir);
 
   /* Assume failure */
   ret=1;
 
   if(item==0)
     {
-      isa="homedir";
-
       /* The homedir must be x00, a directory, and owned by the user. */
 
       if(S_ISDIR(statbuf.st_mode))
@@ -930,11 +1016,6 @@ check_permissions(const char *path,int item)
     }
   else if(item==1 || item==2)
     {
-      if(item==1)
-       isa="configuration file";
-      else
-       isa="extension";
-
       /* The options or extension file.  Okay unless it or its
         containing directory is group or other writable or not owned
         by us or root. */
@@ -982,23 +1063,57 @@ check_permissions(const char *path,int item)
   if(!checkonly)
     {
       if(own)
-       log_info(_("WARNING: unsafe ownership on %s \"%s\"\n"),
-                isa,tmppath);
+       {
+         if(item==0)
+           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);
+         else
+           log_info(_("WARNING: unsafe ownership on "
+                      "extension \"%s\"\n"),tmppath);
+       }
       if(perm)
-       log_info(_("WARNING: unsafe permissions on %s \"%s\"\n"),
-                isa,tmppath);
+       {
+         if(item==0)
+           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);
+         else
+           log_info(_("WARNING: unsafe permissions on "
+                      "extension \"%s\"\n"),tmppath);
+       }
       if(enc_dir_own)
-       log_info(_("WARNING: unsafe enclosing directory "
-                  "ownership on %s \"%s\"\n"),
-                isa,tmppath);
+       {
+         if(item==0)
+           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);
+         else
+           log_info(_("WARNING: unsafe enclosing directory ownership on "
+                      "extension \"%s\"\n"),tmppath);
+       }
       if(enc_dir_perm)
-       log_info(_("WARNING: unsafe enclosing directory "
-                  "permissions on %s \"%s\"\n"),
-                isa,tmppath);
+       {
+         if(item==0)
+           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);
+         else
+           log_info(_("WARNING: unsafe enclosing directory permissions on "
+                      "extension \"%s\"\n"),tmppath);
+       }
     }
 
  end:
-  m_free(tmppath);
+  xfree (tmppath);
 
   if(homedir)
     homedir_cache=ret;
@@ -1014,7 +1129,7 @@ int
 main( int argc, char **argv )
 {
     ARGPARSE_ARGS pargs;
-    IOBUF a;
+    iobuf_t a;
     int rc=0;
     int orig_argc;
     char **orig_argv;
@@ -1038,6 +1153,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 *cert_digest_string = NULL;
     char *s2k_cipher_string = NULL;
     char *s2k_digest_string = NULL;
@@ -1048,27 +1164,41 @@ main( int argc, char **argv )
     int pwfd = -1;
     int with_fpr = 0; /* make an option out of --fingerprint */
     int any_explicit_recipient = 0;
-  #ifdef USE_SHM_COPROCESSING
+#ifdef USE_SHM_COPROCESSING
     ulong requested_shm_size=0;
-  #endif
+#endif
 
-  #ifdef __riscos__
+#ifdef __riscos__
     riscos_global_defaults();
     opt.lock_once = 1;
-  #endif /* __riscos__ */
+#endif /* __riscos__ */
 
     trap_unaligned();
-    secmem_set_flags( secmem_get_flags() | 2 ); /* suspend warnings */
+    set_strusage (my_strusage);
+    gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+    /* We don't need any locking in libgcrypt unless we use any kind of
+       threading. */
+    gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING);
     /* Please note that we may running SUID(ROOT), so be very CAREFUL
      * when adding any stuff between here and the call to
      * secmem_init()  somewhere after the option parsing
      */
-    log_set_name("gpg");
-    secure_random_alloc(); /* put random number into secure memory */
+    log_set_prefix ("gpg", 1);
+    /* check that the libraries are suitable.  Do it here because the
+       option parse may need services of the library */
+    if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
+      {
+        log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
+                   NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
+      }
+
+    gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
+
     may_coredump = disable_core_dumps();
-    init_signals();
-    create_dotlock(NULL); /* register locking cleanup */
+    gnupg_init_signals (0, emergency_cleanup);
+    create_dotlock (NULL); /* register locking cleanup */
     i18n_init();
+
     opt.command_fd = -1; /* no command fd */
     opt.compress = -1; /* defaults to standard compress level */
     /* note: if you change these lines, look at oOpenPGP */
@@ -1078,28 +1208,39 @@ main( int argc, char **argv )
     opt.def_compress_algo = -1;
     opt.s2k_mode = 3; /* iterated+salted */
     opt.s2k_digest_algo = DIGEST_ALGO_SHA1;
+#ifdef USE_CAST5
     opt.s2k_cipher_algo = CIPHER_ALGO_CAST5;
+#else
+    opt.s2k_cipher_algo = CIPHER_ALGO_3DES;
+#endif
     opt.completes_needed = 1;
     opt.marginals_needed = 3;
     opt.max_cert_depth = 5;
     opt.pgp2_workarounds = 1;
     opt.force_v3_sigs = 1;
     opt.escape_from = 1;
-    opt.import_options=0;
+    opt.import_options=IMPORT_SK2PK;
     opt.export_options=
       EXPORT_INCLUDE_NON_RFC|EXPORT_INCLUDE_ATTRIBUTES;
-    opt.keyserver_options.import_options=IMPORT_REPAIR_HKP_SUBKEY_BUG;
+    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;
-#if defined (__MINGW32__) || defined (__CYGWIN32__)
-    opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
+    opt.keyserver_options.include_revoked=1;
+    opt.keyserver_options.try_dns_srv=1;
+    opt.verify_options=VERIFY_SHOW_POLICY|VERIFY_SHOW_NOTATION;
+    opt.trust_model=TM_AUTO;
+    opt.mangle_dos_filenames = 1;
+    opt.use_agent = 1;
+
+#if defined (__MINGW32__)
+    set_homedir ( read_w32_registry_string( NULL,
+                                    "Software\\GNU\\GnuPG", "HomeDir" ));
 #else
-    opt.homedir = getenv("GNUPGHOME");
+    set_homedir ( getenv("GNUPGHOME") );
 #endif
-    if( !opt.homedir || !*opt.homedir ) {
-       opt.homedir = GNUPG_HOMEDIR;
-    }
+    if( !*opt.homedir )
+       set_homedir ( GNUPG_HOMEDIR );
 
     /* check whether we have a config file on the commandline */
     orig_argc = argc;
@@ -1119,10 +1260,20 @@ main( int argc, char **argv )
        else if( pargs.r_opt == oNoOptions )
            default_config = 0; /* --no-options */
        else if( pargs.r_opt == oHomedir )
-           opt.homedir = pargs.r.ret_str;
+           set_homedir ( pargs.r.ret_str );
        else if( pargs.r_opt == oNoPermissionWarn )
            opt.no_perm_warn=1;
-      #ifdef USE_SHM_COPROCESSING
+       else if (pargs.r_opt == oStrict )
+         {
+           opt.strict=1;
+           log_set_strict(1);
+         }
+       else if (pargs.r_opt == oNoStrict )
+         {
+           opt.strict=0;
+           log_set_strict(0);
+         }
+#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 */
@@ -1134,17 +1285,17 @@ main( int argc, char **argv )
             * initialized when init_shm_coprocessing() is called */
            set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) );
        }
-      #endif
+#endif
     }
 
 #ifdef HAVE_DOSISH_SYSTEM
     if ( strchr (opt.homedir,'\\') ) {
-        char *d, *buf = m_alloc (strlen (opt.homedir)+1);
+        char *d, *buf = xmalloc (strlen (opt.homedir)+1);
         const char *s = opt.homedir;
         for (d=buf,s=opt.homedir; *s; s++)
             *d++ = *s == '\\'? '/': *s;
         *d = 0;
-        opt.homedir = buf;
+        set_homedir (buf);
     }
 #endif
 #ifdef USE_SHM_COPROCESSING
@@ -1152,24 +1303,37 @@ main( int argc, char **argv )
        init_shm_coprocessing(requested_shm_size, 1 );
     }
 #endif
-    /* initialize the secure memory. */
-    secmem_init( 16384 );
+    /* Initialize the secure memory. */
+    gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
     maybe_setuid = 0;
     /* Okay, we are now working under our real uid */
 
+    /* malloc hooks go here ... */
+    assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
+
+    set_native_charset (NULL); /* Try to auto set the character set */
+
     if( default_config )
       {
-       configname = make_filename(opt.homedir, "gpg" EXTSEP_S "conf", NULL );
+       /* 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))
+         {
+           xfree (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 );
             if (!access (p, R_OK))
               log_info (_("NOTE: old default options file `%s' ignored\n"), p);
-            m_free (p);
+            xfree (p);
           }
         else
           { /* Keep on using the old default one. */
-            m_free (configname);
+            xfree (configname);
             configname = make_filename(opt.homedir, "options", NULL );
           }
       }
@@ -1208,7 +1372,7 @@ main( int argc, char **argv )
                                    configname, strerror(errno) );
                g10_exit(2);
            }
-           m_free(configname); configname = NULL;
+           xfree (configname); configname = NULL;
        }
        if( parse_debug && configname )
            log_info(_("reading options from `%s'\n"), configname );
@@ -1272,11 +1436,16 @@ main( int argc, char **argv )
          case aListTrustPath: set_cmd( &cmd, aListTrustPath); break;
          case aDeArmor: set_cmd( &cmd, aDeArmor); break;
          case aEnArmor: set_cmd( &cmd, aEnArmor); break;
+         case aListOwnerTrust:
+           deprecated_warning(configname,configlineno,
+                              "--list-ownertrust","--export-ownertrust","");
          case aExportOwnerTrust: set_cmd( &cmd, aExportOwnerTrust); break;
          case aImportOwnerTrust: set_cmd( &cmd, aImportOwnerTrust); break;
           case aPipeMode: set_cmd( &cmd, aPipeMode); break;
           case aRebuildKeydbCaches: set_cmd( &cmd, aRebuildKeydbCaches); break;
 
+          case aChangePIN: set_cmd (&cmd, aChangePIN); break;
+
          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;
@@ -1293,7 +1462,7 @@ main( int argc, char **argv )
             opt.use_agent = 1;
 #else /* __riscos__ */
             opt.use_agent = 0;
-            not_implemented("use-agent");
+            riscos_not_implemented("use-agent");
 #endif /* __riscos__ */
             break;
           case oNoUseAgent: opt.use_agent = 0; break;
@@ -1301,7 +1470,11 @@ main( int argc, char **argv )
          case oAnswerYes: opt.answer_yes = 1; break;
          case oAnswerNo: opt.answer_no = 1; break;
          case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
-         case oShowKeyring: opt.show_keyring = 1; break;
+         case oPrimaryKeyring:
+           sl=append_to_strlist( &nrings, pargs.r.ret_str);
+           sl->flags=2;
+           break;
+         case oShowKeyring: opt.list_options|=LIST_SHOW_KEYRING; break;
          case oDebug: opt.debug |= pargs.r.ret_ulong; break;
          case oDebugAll: opt.debug = ~0; break;
          case oStatusFD:
@@ -1309,7 +1482,7 @@ main( int argc, char **argv )
             break;
 #ifdef __riscos__
          case oStatusFile:
-            set_status_fd( iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 1), 1) );
+            set_status_fd( iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 1), 1) );
             break;
 #endif /* __riscos__ */
          case oAttributeFD:
@@ -1317,17 +1490,16 @@ main( int argc, char **argv )
             break;
 #ifdef __riscos__
          case oAttributeFile:
-            set_attrib_fd(iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 1), 1) );
+            set_attrib_fd(iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 1), 1) );
             break;
 #endif /* __riscos__ */
          case oLoggerFD:
-            log_set_logfile( NULL,
-                             iobuf_translate_file_handle (pargs.r.ret_int, 1) );
+            log_set_fd (iobuf_translate_file_handle (pargs.r.ret_int, 1));
             break;
 #ifdef __riscos__
          case oLoggerFile:
             log_set_logfile( NULL,
-                             iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 1), 1) );
+                             iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 1), 1) );
             break;
 #endif /* __riscos__ */
          case oWithFingerprint:
@@ -1338,8 +1510,8 @@ main( int argc, char **argv )
          case oOptions:
            /* config files may not be nested (silently ignore them) */
            if( !configfp ) {
-               m_free(configname);
-               configname = m_strdup(pargs.r.ret_str);
+               xfree (configname);
+               configname = xstrdup (pargs.r.ret_str);
                goto next_pass;
            }
            break;
@@ -1349,11 +1521,12 @@ main( int argc, char **argv )
          case oNoGreeting: nogreeting = 1; break;
          case oNoVerbose: g10_opt_verbose = 0;
                           opt.verbose = 0; opt.list_sigs=0; break;
-         case oQuickRandom: quick_random_gen(1); break;
+      /* disabled for now: 
+          case oQuickRandom: quick_random_gen(1); break; */
          case oSKComments: opt.sk_comments=1; break;
          case oNoSKComments: opt.sk_comments=0; break;
-         case oNoVersion: opt.no_version=1; break;
          case oEmitVersion: opt.no_version=0; break;
+         case oNoEmitVersion: opt.no_version=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;
@@ -1364,11 +1537,11 @@ main( int argc, char **argv )
                        opt.def_recipient = make_username(pargs.r.ret_str);
                    break;
          case oDefRecipientSelf:
-                   m_free(opt.def_recipient); opt.def_recipient = NULL;
+                   xfree (opt.def_recipient); opt.def_recipient = NULL;
                    opt.def_recipient_self = 1;
                    break;
          case oNoDefRecipient:
-                   m_free(opt.def_recipient); opt.def_recipient = NULL;
+                   xfree (opt.def_recipient); opt.def_recipient = NULL;
                    opt.def_recipient_self = 0;
                    break;
          case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
@@ -1378,13 +1551,37 @@ main( int argc, char **argv )
          case oWithColons: opt.with_colons=':'; break;
 
          case oSkipVerify: opt.skip_verify=1; break;
-         case oCompressAlgo: opt.def_compress_algo = pargs.r.ret_int; break;
          case oCompressKeys: opt.compress_keys = 1; break;
          case aListSecretKeys: set_cmd( &cmd, aListSecretKeys); break;
-         case oAlwaysTrust: opt.always_trust = 1; break;
+           /* There are many programs (like mutt) that call gpg with
+              --always-trust so keep this option around for a long
+              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);
+           break;
+         case oForceOwnertrust:
+           log_info(_("NOTE: %s is not for normal use!\n"),
+                    "--force-ownertrust");
+           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);
+               opt.force_ownertrust=0;
+             }
+           break;
          case oLoadExtension:
 #ifndef __riscos__
-#ifdef USE_DYNAMIC_LINKING
+#if defined(USE_DYNAMIC_LINKING) || defined(__MINGW32__)
            if(check_permissions(pargs.r.ret_str,2))
              log_info(_("cipher extension \"%s\" not loaded due to "
                         "unsafe permissions\n"),pargs.r.ret_str);
@@ -1393,12 +1590,11 @@ main( int argc, char **argv )
                                        pargs.r.ret_str);
 #endif
 #else /* __riscos__ */
-            not_implemented("load-extension");
+            riscos_not_implemented("load-extension");
 #endif /* __riscos__ */
            break;
          case oRFC1991:
-           opt.rfc1991 = 1;
-           opt.rfc2440 = 0;
+           opt.compliance = CO_RFC1991;
            opt.force_v4_certs = 0;
            opt.disable_mdc = 1;
            opt.escape_from = 1;
@@ -1406,8 +1602,7 @@ main( int argc, char **argv )
          case oOpenPGP:
            /* TODO: When 2440bis becomes a RFC, these may need
                changing. */
-           opt.rfc1991 = 0;
-           opt.rfc2440 = 1;
+           opt.compliance = CO_RFC2440;
            opt.disable_mdc = 1;
            opt.allow_non_selfsigned_uid = 1;
            opt.allow_freeform_uid = 1;
@@ -1420,30 +1615,27 @@ main( int argc, char **argv )
            opt.def_cipher_algo = 0;
            opt.def_digest_algo = 0;
            opt.cert_digest_algo = 0;
-           opt.def_compress_algo = 1;
+           opt.def_compress_algo = -1;
             opt.s2k_mode = 3; /* iterated+salted */
            opt.s2k_digest_algo = DIGEST_ALGO_SHA1;
-           opt.s2k_cipher_algo = CIPHER_ALGO_CAST5;
+           opt.s2k_cipher_algo = CIPHER_ALGO_3DES;
            break;
-         case oPGP2: opt.pgp2 = 1; break;
-         case oNoPGP2: opt.pgp2 = 0; break;
-         case oPGP6: opt.pgp6 = 1; break;
-         case oNoPGP6: opt.pgp6 = 0; break;
-         case oPGP7: opt.pgp7 = 1; break;
-         case oNoPGP7: opt.pgp7 = 0; break;
-         case oEmuChecksumBug: opt.emulate_bugs |= EMUBUG_GPGCHKSUM; break;
-         case oEmu3DESS2KBug:  opt.emulate_bugs |= EMUBUG_3DESS2K; break;
+         case oPGP2:  opt.compliance = CO_PGP2;  break;
+         case oPGP6:  opt.compliance = CO_PGP6;  break;
+         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 oRunAsShmCP:
 #ifndef __riscos__
-         #ifndef USE_SHM_COPROCESSING
+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
+endif
 #else /* __riscos__ */
-            not_implemented("run-as-shm-coprocess");
+            riscos_not_implemented("run-as-shm-coprocess");
 #endif /* __riscos__ */
            break;
          case oSetFilename: opt.set_filename = pargs.r.ret_str; break;
@@ -1455,14 +1647,27 @@ main( int argc, char **argv )
            break;
          case oSigPolicyURL: add_policy_url(pargs.r.ret_str,0); break;
          case oCertPolicyURL: add_policy_url(pargs.r.ret_str,1); break;
-          case oShowPolicyURL: opt.show_policy_url=1; break;
-         case oNoShowPolicyURL: opt.show_policy_url=0; break;
+          case oShowPolicyURL:
+           opt.list_options|=LIST_SHOW_POLICY;
+           opt.verify_options|=VERIFY_SHOW_POLICY;
+           break;
+         case oNoShowPolicyURL:
+           opt.list_options&=~LIST_SHOW_POLICY;
+           opt.verify_options&=~VERIFY_SHOW_POLICY;
+           break;
          case oUseEmbeddedFilename: opt.use_embedded_filename = 1; break;
          case oComment: opt.comment_string = pargs.r.ret_str; break;
          case oDefaultComment: opt.comment_string = NULL; break;
          case oThrowKeyid: opt.throw_keyid = 1; break;
-         case oShowPhotos: opt.show_photos = 1; break;
-         case oNoShowPhotos: opt.show_photos = 0; break;
+         case oNoThrowKeyid: opt.throw_keyid = 0; break;
+         case oShowPhotos: 
+           opt.list_options|=LIST_SHOW_PHOTOS;
+           opt.verify_options|=VERIFY_SHOW_PHOTOS;
+           break;
+         case oNoShowPhotos:
+           opt.list_options&=~LIST_SHOW_PHOTOS;
+           opt.verify_options&=~VERIFY_SHOW_PHOTOS;
+           break;
          case oPhotoViewer: opt.photo_viewer = pargs.r.ret_str; break;
          case oForceV3Sigs: opt.force_v3_sigs = 1; break;
          case oNoForceV3Sigs: opt.force_v3_sigs = 0; break;
@@ -1473,20 +1678,30 @@ main( int argc, char **argv )
          case oDisableMDC: opt.disable_mdc = 1; break;
          case oNoDisableMDC: opt.disable_mdc = 0; 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;
+         case oS2KDigest: s2k_digest_string = xstrdup (pargs.r.ret_str); break;
+         case oS2KCipher: s2k_cipher_string = xstrdup (pargs.r.ret_str); break;
           case oSimpleSKChecksum: opt.simple_sk_checksum = 1; break;
          case oNoEncryptTo: opt.no_encrypt_to = 1; break;
          case oEncryptTo: /* store the recipient in the second list */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
            sl->flags = 1;
            break;
+         case oHiddenEncryptTo: /* store the recipient in the second list */
+           sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
+           sl->flags = 1|2;
+           break;
          case oRecipient: /* store the recipient */
            add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
             any_explicit_recipient = 1;
            break;
+         case oHiddenRecipient: /* store the recipient with a flag */
+           sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
+           sl->flags = 2;
+            any_explicit_recipient = 1;
+           break;
          case oTextmodeShort: opt.textmode = 2; break;
          case oTextmode: opt.textmode=1;  break;
+         case oNoTextmode: opt.textmode=0;  break;
          case oExpert: opt.expert = 1; break;
          case oNoExpert: opt.expert = 0; break;
          case oAskSigExpire: opt.ask_sig_expire = 1; break;
@@ -1502,7 +1717,7 @@ main( int argc, char **argv )
             break;
 #ifdef __riscos__
          case oPasswdFile:
-            pwfd = iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 0), 0);
+            pwfd = iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 0), 0);
             break;
 #endif /* __riscos__ */
          case oCommandFD:
@@ -1510,16 +1725,43 @@ main( int argc, char **argv )
             break;
 #ifdef __riscos__
          case oCommandFile:
-            opt.command_fd = iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 0), 0);
+            opt.command_fd = iobuf_translate_file_handle ( riscos_fdopenfile (pargs.r.ret_str, 0), 0);
             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 oCertDigestAlgo: cert_digest_string = m_strdup(pargs.r.ret_str); break;
-         case oNoSecmemWarn: secmem_set_flags( secmem_get_flags() | 1 ); break;
+         case oCipherAlgo: def_cipher_string = xstrdup (pargs.r.ret_str); break;
+         case oDigestAlgo: def_digest_string = xstrdup (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
+              versions that took the compress algorithm number. */
+           {
+             char *pt=pargs.r.ret_str;
+             while(*pt)
+               {
+                 if(!isdigit(*pt))
+                   break;
+
+                 pt++;
+               }
+
+             if(*pt=='\0')
+               {
+                 def_compress_string=xmalloc (strlen(pargs.r.ret_str)+2);
+                 strcpy(def_compress_string,"Z");
+                 strcat(def_compress_string,pargs.r.ret_str);
+               }
+             else
+               def_compress_string = xstrdup (pargs.r.ret_str);
+           }
+           break;
+         case oCertDigestAlgo: cert_digest_string = xstrdup (pargs.r.ret_str); break;
+         case oNoSecmemWarn:
+#warning add secmem_get_flags
+/*              secmem_set_flags( secmem_get_flags() | 1 ); */
+            break;
          case oNoPermissionWarn: opt.no_perm_warn=1; break;
          case oNoMDCWarn: opt.no_mdc_warn=1; break;
-         case oCharset:
+          case oCharset:
            if( set_native_charset( pargs.r.ret_str ) )
                log_error(_("%s is not a valid character set\n"),
                                                    pargs.r.ret_str);
@@ -1533,11 +1775,11 @@ main( int argc, char **argv )
 #ifndef __riscos__
            opt.lock_once = 0;
 #else /* __riscos__ */
-            not_implemented("lock-multiple");
+            riscos_not_implemented("lock-multiple");
 #endif /* __riscos__ */
             break;
          case oKeyServer:
-           opt.keyserver_uri=m_strdup(pargs.r.ret_str);
+           opt.keyserver_uri=xstrdup (pargs.r.ret_str);
            if(parse_keyserver_uri(pargs.r.ret_str,configname,configlineno))
              log_error(_("could not parse keyserver URI\n"));
            break;
@@ -1564,6 +1806,49 @@ main( int argc, char **argv )
                  log_error(_("invalid export options\n"));
              }
            break;
+         case oListOptions:
+           {
+             struct parse_options lopts[]=
+               {
+                 {"show-photos",LIST_SHOW_PHOTOS},
+                 {"show-policy-url",LIST_SHOW_POLICY},
+                 {"show-notation",LIST_SHOW_NOTATION},
+                 {"show-keyring",LIST_SHOW_KEYRING},
+                 {"show-validity",LIST_SHOW_VALIDITY},
+                 {"show-long-keyid",LIST_SHOW_LONG_KEYID},
+                 {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"));
+               }
+           }
+           break;
+         case oVerifyOptions:
+           {
+             struct parse_options vopts[]=
+               {
+                 {"show-photos",VERIFY_SHOW_PHOTOS},
+                 {"show-policy-url",VERIFY_SHOW_POLICY},
+                 {"show-notation",VERIFY_SHOW_NOTATION},
+                 {NULL,0}
+               };
+
+             if(!parse_options(pargs.r.ret_str,&opt.verify_options,vopts))
+               {
+                 if(configname)
+                   log_error(_("%s:%d: invalid verify options\n"),
+                             configname,configlineno);
+                 else
+                   log_error(_("invalid verify options\n"));
+               }
+           }
+           break;
          case oTempDir: opt.temp_dir=pargs.r.ret_str; break;
          case oExecPath:
            if(set_exec_path(pargs.r.ret_str,0))
@@ -1577,16 +1862,30 @@ main( int argc, char **argv )
            break;
          case oSigNotation: add_notation_data( pargs.r.ret_str, 0 ); break;
          case oCertNotation: add_notation_data( pargs.r.ret_str, 1 ); break;
-         case oShowNotation: opt.show_notation=1; break;
-         case oNoShowNotation: opt.show_notation=0; break;
+         case oShowNotation:
+           opt.list_options|=LIST_SHOW_NOTATION;
+           opt.verify_options|=VERIFY_SHOW_NOTATION;
+           break;
+         case oNoShowNotation:
+           opt.list_options&=~LIST_SHOW_NOTATION;
+           opt.verify_options&=~VERIFY_SHOW_NOTATION;
+           break;
          case oUtf8Strings: utf8_strings = 1; break;
          case oNoUtf8Strings: utf8_strings = 0; break;
          case oDisableCipherAlgo:
-               disable_cipher_algo( string_to_cipher_algo(pargs.r.ret_str) );
-               break;
+            {
+              int algo = gcry_cipher_map_name (pargs.r.ret_str);
+              gcry_cipher_ctl (NULL, GCRYCTL_DISABLE_ALGO,
+                               &algo, sizeof algo);
+            }
+            break;
          case oDisablePubkeyAlgo:
-               disable_pubkey_algo( string_to_pubkey_algo(pargs.r.ret_str) );
-               break;
+            {
+              int algo = gcry_pk_map_name (pargs.r.ret_str);
+              gcry_pk_ctl (GCRYCTL_DISABLE_ALGO,
+                           &algo, sizeof algo );
+            }
+            break;
           case oNoSigCache: opt.no_sig_cache = 1; break;
           case oNoSigCreateCheck: opt.no_sig_create_check = 1; break;
          case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break;
@@ -1647,12 +1946,21 @@ main( int argc, char **argv )
           case oPersonalCompressPreferences:
            pers_compress_list=pargs.r.ret_str;
            break;
+          case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
           case oDisplay: opt.display = pargs.r.ret_str; break;
           case oTTYname: opt.ttyname = pargs.r.ret_str; break;
           case oTTYtype: opt.ttytype = pargs.r.ret_str; break;
           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 oStrict: opt.strict=1; log_set_strict(1); break;
+         case oNoStrict: opt.strict=0; log_set_strict(0); break;
+
+          case oMangleDosFilenames: opt.mangle_dos_filenames = 1; break;
+          case oNoMangleDosFilenames: opt.mangle_dos_filenames = 0; break;
+
+          case oEnableProgressFilter: opt.enable_progress_filter = 1; break;
+
          default : pargs.err = configfp? 1:2; break;
        }
     }
@@ -1660,10 +1968,10 @@ main( int argc, char **argv )
     if( configfp ) {
        fclose( configfp );
        configfp = NULL;
-       m_free(configname); configname = NULL;
+       xfree (configname); configname = NULL;
        goto next_pass;
     }
-    m_free( configname ); configname = NULL;
+    xfree ( configname ); configname = NULL;
     if( log_get_errorcount(0) )
        g10_exit(2);
     if( nogreeting )
@@ -1674,13 +1982,19 @@ main( int argc, char **argv )
                        strusage(11), strusage(13), strusage(14) );
        fprintf(stderr, "%s\n", strusage(15) );
     }
-  #ifdef IS_DEVELOPMENT_VERSION
+#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");
     }
-  #endif
+#endif
+
+#warning locking does not work - disabled
+    disable_dotlock ();
+
+    if (opt.verbose > 2)
+        log_info ("using character set `%s'\n", get_native_charset ());
 
     if( may_coredump && !opt.quiet )
        log_info(_("WARNING: program may create a core file!\n"));
@@ -1709,138 +2023,148 @@ main( int argc, char **argv )
     if( opt.batch )
        tty_batchmode( 1 );
 
+#warning fix that
+#if 0
     secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */
-
+#endif
     set_debug();
-    g10_opt_homedir = opt.homedir;
 
     /* Do these after the switch(), so they can override settings. */
-    if(opt.pgp2 && (opt.pgp6 || opt.pgp7))
-      log_error(_("%s not allowed with %s!\n"),
-               "--pgp2",opt.pgp6?"--pgp6":"--pgp7");
-    else
+    if(PGP2)
       {
-       if(opt.pgp2)
+       int unusable=0;
+
+       if(cmd==aSign && !detached_sig)
+         {
+           log_info(_("you can only make detached or clear signatures "
+                      "while in --pgp2 mode\n"));
+           unusable=1;
+         }
+       else if(cmd==aSignEncr || cmd==aSignSym)
+         {
+           log_info(_("you can't sign and encrypt at the "
+                      "same time while in --pgp2 mode\n"));
+           unusable=1;
+         }
+       else if(argc==0 && (cmd==aSign || cmd==aEncr || cmd==aSym))
          {
-           int unusable=0;
+           log_info(_("you must use files (and not a pipe) when "
+                      "working with --pgp2 enabled.\n"));
+           unusable=1;
+         }
+       else if(cmd==aEncr || cmd==aSym)
+         {
+           /* Everything else should work without IDEA (except using
+              a secret key encrypted with IDEA and setting an IDEA
+              preference, but those have their own error
+              messages). */
 
-           if(cmd==aSign && !detached_sig)
+           if(openpgp_cipher_test_algo (CIPHER_ALGO_IDEA))
              {
-               log_info(_("you can only make detached or clear signatures "
-                          "while in --pgp2 mode\n"));
+               log_info(_("encrypting a message in --pgp2 mode requires "
+                          "the IDEA cipher\n"));
+               idea_cipher_warn(1);
                unusable=1;
              }
-           else if(cmd==aSignEncr || cmd==aSignSym)
+           else if(cmd==aSym)
              {
-               log_info(_("you can't sign and encrypt at the "
-                          "same time while in --pgp2 mode\n"));
-               unusable=1;
-             }
-           else if(argc==0 && (cmd==aSign || cmd==aEncr || cmd==aSym))
-             {
-               log_info(_("you must use files (and not a pipe) when "
-                          "working with --pgp2 enabled.\n"));
-               unusable=1;
-             }
-           else if(cmd==aEncr || cmd==aSym)
-             {
-               /* Everything else should work without IDEA (except using
-                  a secret key encrypted with IDEA and setting an IDEA
-                  preference, but those have their own error
-                  messages). */
-
-               if(check_cipher_algo(CIPHER_ALGO_IDEA))
-                 {
-                   log_info(_("encrypting a message in --pgp2 mode requires "
-                              "the IDEA cipher\n"));
-                   idea_cipher_warn(1);
-                   unusable=1;
-                 }
-               else if(cmd==aSym)
-                 {
-                   m_free(def_cipher_string);
-                   def_cipher_string = m_strdup("idea");
-                 }
+               /* This only sets IDEA for symmetric encryption
+                  since it is set via select_algo_from_prefs for
+                  pk encryption. */
+               xfree (def_cipher_string);
+               def_cipher_string = xstrdup ("idea");
              }
 
-           if(unusable)
-             {
-               log_info(_("this message may not be usable by %s\n"),
-                        "PGP 2.x");
-               opt.pgp2=0;
-             }
-           else
-             {
-               opt.rfc1991 = 1;
-               opt.rfc2440 = 0;
-               opt.force_mdc = 0;
-               opt.disable_mdc = 1;
-               opt.force_v4_certs = 0;
-               opt.sk_comments = 0;
-               opt.escape_from = 1;
-               opt.force_v3_sigs = 1;
-               opt.pgp2_workarounds = 1;
-               opt.ask_sig_expire = 0;
-               opt.ask_cert_expire = 0;
-               m_free(def_digest_string);
-               def_digest_string = m_strdup("md5");
-               opt.def_compress_algo = 1;
-             }
+           /* PGP2 can't handle the output from the textmode
+              filter, so we disable it for anything that could
+              create a literal packet (only encryption and
+              symmetric encryption, since we disable signing
+              above). */
+           if(!unusable)
+             opt.textmode=0;
          }
 
-       if(opt.pgp6 || opt.pgp7)
+       if(unusable)
+         compliance_failure();
+       else
          {
-           opt.sk_comments=0;
-           opt.escape_from=1;
-           opt.force_v3_sigs=1;
-           opt.ask_sig_expire=0;
-           opt.def_compress_algo=1;
-
-           if(opt.pgp6) /* pgp7 has MDC */
-             {
-               opt.force_mdc=0;
-               opt.disable_mdc=1;
-             }
+           opt.force_mdc = 0;
+           opt.disable_mdc = 1;
+           opt.force_v4_certs = 0;
+           opt.sk_comments = 0;
+           opt.escape_from = 1;
+           opt.force_v3_sigs = 1;
+           opt.pgp2_workarounds = 1;
+           opt.ask_sig_expire = 0;
+           opt.ask_cert_expire = 0;
+           xfree (def_digest_string);
+           def_digest_string = xstrdup ("md5");
+           opt.def_compress_algo = 1;
          }
       }
+    else if(PGP6)
+      {
+       opt.sk_comments=0;
+       opt.escape_from=1;
+       opt.force_v3_sigs=1;
+       opt.ask_sig_expire=0;
+       opt.force_mdc=0;
+       opt.disable_mdc=1;
+      }
+    else if(PGP7)
+      {
+       opt.sk_comments=0;
+       opt.escape_from=1;
+       opt.force_v3_sigs=1;
+       opt.ask_sig_expire=0;
+      }
+    else if(PGP8)
+      {
+       opt.escape_from=1;
+      }
 
     /* must do this after dropping setuid, because string_to...
      * may try to load an module */
     if( def_cipher_string ) {
-       opt.def_cipher_algo = string_to_cipher_algo(def_cipher_string);
+       opt.def_cipher_algo = gcry_cipher_map_name (def_cipher_string);
        if(opt.def_cipher_algo==0 &&
-          ascii_strcasecmp(def_cipher_string,"idea")==0)
+          (ascii_strcasecmp(def_cipher_string,"idea")==0
+           || ascii_strcasecmp(def_cipher_string,"s1")==0))
          idea_cipher_warn(1);
-       m_free(def_cipher_string); def_cipher_string = NULL;
-       if( check_cipher_algo(opt.def_cipher_algo) )
+       xfree (def_cipher_string); def_cipher_string = NULL;
+       if( openpgp_cipher_test_algo (opt.def_cipher_algo) )
            log_error(_("selected cipher algorithm is invalid\n"));
     }
     if( def_digest_string ) {
-       opt.def_digest_algo = string_to_digest_algo(def_digest_string);
-       m_free(def_digest_string); def_digest_string = NULL;
-       if( check_digest_algo(opt.def_digest_algo) )
+       opt.def_digest_algo = gcry_md_map_name (def_digest_string);
+       xfree (def_digest_string); def_digest_string = NULL;
+       if( openpgp_md_test_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);
+       xfree (def_compress_string); def_compress_string = NULL;
+       if( check_compress_algo(opt.def_compress_algo) )
+           log_error(_("selected compression algorithm is invalid\n"));
+    }
     if( cert_digest_string ) {
-       opt.cert_digest_algo = string_to_digest_algo(cert_digest_string);
-       m_free(cert_digest_string); cert_digest_string = NULL;
-       if( check_digest_algo(opt.cert_digest_algo) )
+       opt.cert_digest_algo = gcry_md_map_name (cert_digest_string);
+       xfree (cert_digest_string); cert_digest_string = NULL;
+       if( openpgp_md_test_algo(opt.cert_digest_algo) )
            log_error(_("selected certification 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) )
+       opt.s2k_cipher_algo = gcry_cipher_map_name (s2k_cipher_string);
+       xfree (s2k_cipher_string); s2k_cipher_string = NULL;
+       if( openpgp_cipher_test_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) )
+       opt.s2k_digest_algo = gcry_md_map_name (s2k_digest_string);
+       xfree (s2k_digest_string); s2k_digest_string = NULL;
+       if( openpgp_md_test_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"), 0, 2);
     if( opt.completes_needed < 1 )
        log_error(_("completes-needed must be greater than 0\n"));
     if( opt.marginals_needed < 2 )
@@ -1884,11 +2208,74 @@ main( int argc, char **argv )
     if( log_get_errorcount(0) )
        g10_exit(2);
 
+    /* Check our chosen algorithms against the list of legal
+       algorithms. */
+
+    if(!GNUPG)
+      {
+       const char *badalg=NULL;
+       preftype_t badtype=PREFTYPE_NONE;
+
+       if (opt.def_cipher_algo
+            && !algo_available (PREFTYPE_SYM,opt.def_cipher_algo,NULL))
+         {
+           badalg = gcry_cipher_algo_name (opt.def_cipher_algo);
+           badtype = PREFTYPE_SYM;
+         }
+       else if (opt.def_digest_algo
+               && !algo_available (PREFTYPE_HASH,opt.def_digest_algo,NULL))
+         {
+           badalg = gcry_md_algo_name (opt.def_digest_algo);
+           badtype = PREFTYPE_HASH;
+         }
+       else if (opt.cert_digest_algo
+                && !algo_available (PREFTYPE_HASH,opt.cert_digest_algo,NULL))
+         {
+           badalg = gcry_md_algo_name (opt.cert_digest_algo);
+           badtype = PREFTYPE_HASH;
+         }
+       else if (opt.def_compress_algo!=-1
+                 && !algo_available (PREFTYPE_ZIP,opt.def_compress_algo,NULL))
+         {
+           badalg = compress_algo_to_string (opt.def_compress_algo);
+           badtype = PREFTYPE_ZIP;
+         }
+
+       if (badalg)
+         {
+           switch(badtype)
+             {
+             case PREFTYPE_SYM:
+               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"),
+                        badalg,compliance_option_string());
+               break;
+             case PREFTYPE_ZIP:
+               log_info(_("you may not use compression algorithm \"%s\" "
+                          "while in %s mode\n"),
+                        badalg,compliance_option_string());
+               break;
+             default:
+               BUG();
+             }
+
+           compliance_failure();
+         }
+      }
+
     /* set the random seed file */
     if( use_random_seed ) {
        char *p = make_filename(opt.homedir, "random_seed", NULL );
+#warning No random seed file yet
+#if 0
        set_random_seed_file(p);
-       m_free(p);
+#endif
+       xfree (p);
     }
 
     if( !cmd && opt.fingerprint && !with_fpr ) {
@@ -1940,7 +2327,7 @@ main( int argc, char **argv )
        if( !nrings || default_keyring )  /* add default ring */
            keydb_add_resource ("pubring" EXTSEP_S "gpg", 0, 0);
        for(sl = nrings; sl; sl = sl->next )
-           keydb_add_resource ( sl->d, 0, 0 );
+           keydb_add_resource ( sl->d, sl->flags, 0 );
       }
     FREE_STRLIST(nrings);
     FREE_STRLIST(sec_nrings);
@@ -1959,20 +2346,14 @@ main( int argc, char **argv )
       case aDeArmor:
       case aEnArmor:
       case aFixTrustDB:
-       break;
-      case aKMode:
-      case aListKeys:
-      case aListSecretKeys:
-      case aCheckKeys:
-       if( opt.with_colons ) /* need this to list the trust */
-           rc = setup_trustdb(1, trustdb_name );
+      case aChangePIN:
        break;
       case aExportOwnerTrust: rc = setup_trustdb( 0, trustdb_name ); break;
       case aListTrustDB: rc = setup_trustdb( argc? 1:0, trustdb_name ); break;
       default: rc = setup_trustdb(1, trustdb_name ); break;
     }
     if( rc )
-       log_error(_("failed to initialize the TrustDB: %s\n"), g10_errstr(rc));
+       log_error(_("failed to initialize the TrustDB: %s\n"), gpg_strerror (rc));
 
 
     switch (cmd) {
@@ -1994,22 +2375,23 @@ main( int argc, char **argv )
        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 ("\b%s: store failed: %s\n",
+                       print_fname_stdin(fname), gpg_strerror (rc) );
        break;
       case aSym: /* encrypt the given file only with the symmetric cipher */
        if( argc > 1 )
            wrong_args(_("--symmetric [filename]"));
        if( (rc = encode_symmetric(fname)) )
-           log_error_f(print_fname_stdin(fname),
-                       "symmetric encryption failed: %s\n",g10_errstr(rc) );
+           log_error ("\b%s: symmetric encryption failed: %s\n",
+                       print_fname_stdin(fname), gpg_strerror (rc) );
        break;
 
       case aEncr: /* encrypt the given file */
        if( argc > 1 )
            wrong_args(_("--encrypt [filename]"));
        if( (rc = encode_crypt(fname,remusr)) )
-           log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
+           log_error("%s: encryption failed: %s\n",
+                      print_fname_stdin(fname), gpg_strerror (rc) );
        break;
 
       case aEncrFiles: /* encrypt the given files */
@@ -2026,12 +2408,12 @@ main( int argc, char **argv )
            if( argc > 1 )
                wrong_args(_("--sign [filename]"));
            if( argc ) {
-               sl = m_alloc_clear( sizeof *sl + strlen(fname));
+               sl = xcalloc (1, sizeof *sl + strlen(fname));
                strcpy(sl->d, fname);
            }
        }
        if( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) )
-           log_error("signing failed: %s\n", g10_errstr(rc) );
+           log_error("signing failed: %s\n", gpg_strerror (rc) );
        free_strlist(sl);
        break;
 
@@ -2039,13 +2421,13 @@ main( int argc, char **argv )
        if( argc > 1 )
            wrong_args(_("--sign --encrypt [filename]"));
        if( argc ) {
-           sl = m_alloc_clear( sizeof *sl + strlen(fname));
+           sl = xcalloc (1, sizeof *sl + strlen(fname));
            strcpy(sl->d, fname);
        }
        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), gpg_strerror (rc) );
        free_strlist(sl);
        break;
 
@@ -2055,7 +2437,7 @@ main( int argc, char **argv )
        rc = sign_symencrypt_file (fname, locusr);
         if (rc)
            log_error("%s: sign+symmetric failed: %s\n",
-                      print_fname_stdin(fname), g10_errstr(rc) );
+                      print_fname_stdin(fname), gpg_strerror (rc) );
        break;
 
       case aClearsign: /* make a clearsig */
@@ -2063,24 +2445,24 @@ main( int argc, char **argv )
            wrong_args(_("--clearsign [filename]"));
        if( (rc = clearsign_file(fname, locusr, NULL)) )
            log_error("%s: clearsign failed: %s\n",
-                      print_fname_stdin(fname), g10_errstr(rc) );
+                      print_fname_stdin(fname), gpg_strerror (rc) );
        break;
 
       case aVerify:
        if( (rc = verify_signatures( argc, argv ) ))
-           log_error("verify signatures failed: %s\n", g10_errstr(rc) );
+           log_error("verify signatures failed: %s\n", gpg_strerror (rc) );
        break;
 
       case aVerifyFiles:
        if( (rc = verify_files( argc, argv ) ))
-           log_error("verify files failed: %s\n", g10_errstr(rc) );
+           log_error("verify files failed: %s\n", gpg_strerror (rc) );
        break;
 
       case aDecrypt:
        if( argc > 1 )
            wrong_args(_("--decrypt [filename]"));
        if( (rc = decrypt_message( fname ) ))
-           log_error("decrypt_message failed: %s\n", g10_errstr(rc) );
+           log_error("decrypt_message failed: %s\n", gpg_strerror (rc) );
        break;
 
       case aDecryptFiles:
@@ -2092,7 +2474,7 @@ main( int argc, char **argv )
            wrong_args(_("--sign-key user-id"));
        username = make_username( fname );
        keyedit_menu(fname, locusr, NULL, 1 );
-       m_free(username);
+       xfree (username);
        break;
 
       case aLSignKey:
@@ -2100,7 +2482,7 @@ main( int argc, char **argv )
            wrong_args(_("--lsign-key user-id"));
        username = make_username( fname );
        keyedit_menu(fname, locusr, NULL, 2 );
-       m_free(username);
+       xfree (username);
        break;
 
       case aNRSignKey:
@@ -2108,7 +2490,7 @@ main( int argc, char **argv )
            wrong_args(_("--nrsign-key user-id"));
        username = make_username( fname );
        keyedit_menu(fname, locusr, NULL, 3 );
-        m_free(username);
+        xfree (username);
         break;
 
       case aNRLSignKey:
@@ -2116,7 +2498,7 @@ main( int argc, char **argv )
            wrong_args(_("--nrlsign-key user-id"));
        username = make_username( fname );
        keyedit_menu(fname, locusr, NULL, 4 );
-        m_free(username);
+        xfree (username);
         break;
 
       case aEditKey: /* Edit a key signature */
@@ -2132,7 +2514,7 @@ main( int argc, char **argv )
        }
        else
            keyedit_menu(username, locusr, NULL, 0 );
-       m_free(username);
+       xfree (username);
        break;
 
       case aDeleteKeys:
@@ -2209,9 +2591,9 @@ main( int argc, char **argv )
        break;
 
       case aFastImport:
+        opt.import_options |= IMPORT_FAST_IMPORT;
       case aImport:
-       import_keys( argc? argv:NULL, argc, (cmd == aFastImport),
-                    NULL, opt.import_options );
+       import_keys( argc? argv:NULL, argc, NULL, opt.import_options );
        break;
 
       case aExport:
@@ -2222,20 +2604,40 @@ main( int argc, char **argv )
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
        if( cmd == aSendKeys )
-           keyserver_export( sl );
+           rc=keyserver_export( sl );
        else if( cmd == aRecvKeys )
-           keyserver_import( sl );
+           rc=keyserver_import( sl );
        else
-           export_pubkeys( sl, opt.export_options );
+           rc=export_pubkeys( sl, opt.export_options );
+       if(rc)
+         {
+           if(cmd==aSendKeys)
+             log_error(_("keyserver send failed: %s\n"),gpg_strerror (rc));
+           else if(cmd==aRecvKeys)
+             log_error(_("keyserver receive failed: %s\n"),gpg_strerror (rc));
+           else
+             log_error(_("key export failed: %s\n"),gpg_strerror (rc));
+         }
        free_strlist(sl);
        break;
 
      case aSearchKeys:
        sl = NULL;
        for( ; argc; argc--, argv++ )
-         append_to_strlist2( &sl, *argv, utf8_strings );
+          {
+            if (utf8_strings)
+              sl = append_to_strlist ( &sl, *argv );
+            else
+              {
+                char *p = native_to_utf8 ( *argv );
+                sl = append_to_strlist( &sl, p );
+                xfree( p );
+              }
+          }
 
-       keyserver_search( sl );
+       rc=keyserver_search( sl );
+       if(rc)
+         log_error(_("keyserver search failed: %s\n"),gpg_strerror (rc));
        free_strlist(sl);
        break;
 
@@ -2243,7 +2645,9 @@ main( int argc, char **argv )
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
-       keyserver_refresh(sl);
+       rc=keyserver_refresh(sl);
+       if(rc)
+         log_error(_("keyserver refresh failed: %s\n"),gpg_strerror (rc));
        free_strlist(sl);
        break;
 
@@ -2268,7 +2672,7 @@ main( int argc, char **argv )
            wrong_args("--gen-revoke user-id");
        username =  make_username(*argv);
        gen_revoke( username );
-       m_free( username );
+       xfree ( username );
        break;
 
       case aDesigRevoke:
@@ -2276,7 +2680,7 @@ main( int argc, char **argv )
            wrong_args("--desig-revoke user-id");
        username =  make_username(*argv);
        gen_desig_revoke( username );
-       m_free( username );
+       xfree ( username );
        break;
 
       case aDeArmor:
@@ -2284,7 +2688,7 @@ main( int argc, char **argv )
            wrong_args("--dearmor [file]");
        rc = dearmor_file( argc? *argv: NULL );
        if( rc )
-           log_error(_("dearmoring failed: %s\n"), g10_errstr(rc));
+           log_error(_("dearmoring failed: %s\n"), gpg_strerror (rc));
        break;
 
       case aEnArmor:
@@ -2292,11 +2696,12 @@ main( int argc, char **argv )
            wrong_args("--enarmor [file]");
        rc = enarmor_file( argc? *argv: NULL );
        if( rc )
-           log_error(_("enarmoring failed: %s\n"), g10_errstr(rc));
+           log_error(_("enarmoring failed: %s\n"), gpg_strerror (rc));
        break;
 
 
       case aPrimegen:
+#if 0 /*FIXME-XXX*/
        {   int mode = argc < 2 ? 0 : atoi(*argv);
 
            if( mode == 1 && argc == 2 ) {
@@ -2308,7 +2713,7 @@ main( int argc, char **argv )
                                             atoi(argv[2]), NULL,NULL ), 1);
            }
            else if( mode == 3 && argc == 3 ) {
-               MPI *factors;
+               gcry_mpi_t *factors;
                mpi_print( stdout, generate_elg_prime(
                                             1, atoi(argv[1]),
                                             atoi(argv[2]), NULL,&factors ), 1);
@@ -2316,7 +2721,7 @@ main( int argc, char **argv )
                mpi_print( stdout, factors[0], 1 ); /* print q */
            }
            else if( mode == 4 && argc == 3 ) {
-               MPI g = mpi_alloc(1);
+               gcry_mpi_t g = mpi_alloc(1);
                mpi_print( stdout, generate_elg_prime(
                                                 0, atoi(argv[1]),
                                                 atoi(argv[2]), g, NULL ), 1);
@@ -2328,6 +2733,7 @@ main( int argc, char **argv )
                wrong_args("--gen-prime mode bits [qbits] ");
            putchar('\n');
        }
+#endif
        break;
 
       case aGenRandom:
@@ -2347,14 +2753,14 @@ main( int argc, char **argv )
                    other tools */
                size_t n = !endless && count < 99? count : 99;
 
-               p = get_random_bits( n*8, level, 0);
-             #ifdef HAVE_DOSISH_SYSTEM
+               p = gcry_random_bytes (n, level);
+#ifdef HAVE_DOSISH_SYSTEM
                setmode ( fileno(stdout), O_BINARY );
-             #endif
+#endif
                 if (opt.armor) {
                     char *tmp = make_radix64_string (p, n);
                     fputs (tmp, stdout);
-                    m_free (tmp);
+                    xfree (tmp);
                     if (n%3 == 1)
                       putchar ('=');
                     if (n%3)
@@ -2362,7 +2768,7 @@ main( int argc, char **argv )
                 } else {
                     fwrite( p, n, 1, stdout );
                 }
-               m_free(p);
+               xfree (p);
                if( !endless )
                    count -= n;
            }
@@ -2376,7 +2782,7 @@ main( int argc, char **argv )
            wrong_args("--print-md algo [files]");
        {
            int all_algos = (**argv=='*' && !(*argv)[1]);
-           int algo = all_algos? 0 : string_to_digest_algo(*argv);
+           int algo = all_algos? 0 : gcry_md_map_name (*argv);
 
            if( !algo && !all_algos )
                log_error(_("invalid hash algorithm `%s'\n"), *argv );
@@ -2433,7 +2839,7 @@ main( int argc, char **argv )
        for( ; argc; argc--, argv++ ) {
            username = make_username( *argv );
            list_trust_path( username );
-           m_free(username);
+           xfree (username);
        }
        break;
 
@@ -2461,6 +2867,15 @@ main( int argc, char **argv )
         keydb_rebuild_caches ();
         break;
 
+    case aChangePIN:
+      if (!argc)
+        change_pin (0);
+      else if (argc == 1)
+        change_pin ( atoi (*argv));
+      else
+        wrong_args ("--change-pin [no]");
+      break;
+
       case aListPackets:
        opt.list_packets=2;
       default:
@@ -2487,7 +2902,7 @@ main( int argc, char **argv )
            }
            rc = proc_packets(NULL, a );
            if( rc )
-               log_error("processing message failed: %s\n", g10_errstr(rc) );
+               log_error("processing message failed: %s\n", gpg_strerror (rc) );
            iobuf_close(a);
        }
        break;
@@ -2500,58 +2915,114 @@ main( int argc, char **argv )
     return 8; /*NEVER REACHED*/
 }
 
+/* Note: This function is used by signal handlers!. */
+static void
+emergency_cleanup (void)
+{
+  gcry_control (GCRYCTL_TERM_SECMEM );
+}
+
 
 void
 g10_exit( int rc )
 {
-    update_random_seed_file();
-    if( opt.debug & DBG_MEMSTAT_VALUE ) {
-       m_print_stats("on exit");
-       random_dump_stats();
-    }
-    if( opt.debug )
-       secmem_dump_stats();
-    secmem_term();
+  /* FIXME-XX update_random_seed_file(); */
+/*      if( opt.debug & DBG_MEMSTAT_VALUE ) { */
+/*          m_print_stats("on exit"); */
+/*     random_dump_stats(); */
+/*      } */
+/*      if( opt.debug ) */
+/*     secmem_dump_stats(); */
+    gcry_control (GCRYCTL_TERM_SECMEM );
     rc = rc? rc : log_get_errorcount(0)? 2 :
                        g10_errors_seen? 1 : 0;
     exit(rc );
 }
 
 
-
-
+/* Pretty-print hex hashes.  This assumes at least an 80-character
+   display, but there are a few other similar assumptions in the
+   display code. */
 static void
-print_hex( byte *p, size_t n )
+print_hex( MD_HANDLE md, int algo, const char *fname )
 {
-    int i;
+  int i,n,count,indent=0;
+  const byte *p;
 
-    if( n == 20 ) {
-       for(i=0; i < n ; i++, i++, p += 2 ) {
-           if( i )
-               putchar(' ');
-           if( i == 10 )
-               putchar(' ');
-           printf("%02X%02X", *p, p[1] );
-       }
+  if(fname)
+    indent=printf("%s: ",fname);
+
+  if(indent>40)
+    {
+      printf("\n");
+      indent=0;
     }
-    else if( n == 24 ) {
-       for(i=0; i < n ; i += 4, p += 4 ) {
-           if( i )
-               putchar(' ');
-           if( i == 12 )
-               putchar(' ');
-           printf("%02X%02X%02X%02X", *p, p[1], p[2], p[3] );
+
+  if(algo==DIGEST_ALGO_RMD160)
+    indent+=printf("RMD160 = ");
+  else if(algo==DIGEST_ALGO_TIGER)
+    indent+=printf(" TIGER = ");
+  else if(algo>0)
+    indent+=printf("%6s = ", gcry_md_algo_name (algo));
+  else
+    algo=abs(algo);
+
+  count=indent;
+
+  p = gcry_md_read (md, algo);
+  n = gcry_md_get_algo_dlen (algo);
+
+  count+=printf("%02X",*p++);
+
+  for(i=1;i<n;i++,p++)
+    {
+      if(n==16)
+       {
+         if(count+2>79)
+           {
+             printf("\n%*s",indent," ");
+             count=indent;
+           }
+         else
+           count+=printf(" ");
+
+         if(!(i%8))
+           count+=printf(" ");
        }
-    }
-    else {
-       for(i=0; i < n ; i++, p++ ) {
-           if( i )
-               putchar(' ');
-           if( i && !(i%8) )
-               putchar(' ');
-           printf("%02X", *p );
+      else if (n==20)
+       {
+         if(!(i%2))
+           {
+             if(count+4>79)
+               {
+                 printf("\n%*s",indent," ");
+                 count=indent;
+               }
+             else
+               count+=printf(" ");
+           }
+
+         if(!(i%10))
+           count+=printf(" ");
+       }
+      else
+       {
+         if(!(i%4))
+           {
+             if(count+8>79)
+               {
+                 printf("\n%*s",indent," ");
+                 count=indent;
+               }
+             else
+               count+=printf(" ");
+           }
        }
+
+      count+=printf("%02X",*p);
     }
+
+  printf("\n");
 }
 
 static void
@@ -2570,8 +3041,8 @@ print_hashline( MD_HANDLE md, int algo, const char *fname )
     }
     putchar(':');
     printf("%d:", algo );
-    p = md_read( md, algo );
-    n = md_digest_length(algo);
+    p = gcry_md_read (md, algo );
+    n = gcry_md_get_algo_dlen (algo);
     for(i=0; i < n ; i++, p++ ) 
         printf("%02X", *p );
     putchar(':');
@@ -2585,76 +3056,86 @@ print_mds( const char *fname, int algo )
     char buf[1024];
     size_t n;
     MD_HANDLE md;
-    char *pname;
 
     if( !fname ) {
        fp = stdin;
-      #ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_DOSISH_SYSTEM
        setmode ( fileno(fp) , O_BINARY );
-      #endif
-       pname = m_strdup("[stdin]: ");
+#endif
     }
     else {
-       pname = m_alloc(strlen(fname)+3);
-       strcpy(stpcpy(pname,fname),": ");
        fp = fopen( fname, "rb" );
     }
     if( !fp ) {
-       log_error("%s%s\n", pname, strerror(errno) );
-       m_free(pname);
+       log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) );
        return;
     }
 
-    md = md_open( 0, 0 );
+    gcry_md_open (&md, 0, 0 );
     if( algo )
-       md_enable( md, algo );
+       gcry_md_enable ( md, algo );
     else {
-       md_enable( md, DIGEST_ALGO_MD5 );
-       md_enable( md, DIGEST_ALGO_SHA1 );
-       md_enable( md, DIGEST_ALGO_RMD160 );
-       if( !check_digest_algo(DIGEST_ALGO_TIGER) )
-           md_enable( md, DIGEST_ALGO_TIGER );
+       gcry_md_enable (md, GCRY_MD_MD5 );
+       gcry_md_enable (md, GCRY_MD_SHA1 );
+       gcry_md_enable (md, GCRY_MD_RMD160 );
+#ifdef USE_TIGER192
+       gcry_md_enable (md, GCRY_MD_TIGER );
+#endif
+#ifdef USE_SHA256
+       gcry_md_enable (md, GCRY_MD_SHA256 );
+#endif
+#ifdef USE_SHA512
+       gcry_md_enable (md, GCRY_MD_SHA384 );
+       gcry_md_enable (md, GCRY_MD_SHA512 );
+#endif
     }
 
     while( (n=fread( buf, 1, DIM(buf), fp )) )
-       md_write( md, buf, n );
+       gcry_md_write (md, buf, n);
     if( ferror(fp) )
-       log_error("%s%s\n", pname, strerror(errno) );
+       log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) );
     else {
-       md_final(md);
+       gcry_md_final (md);
         if ( opt.with_colons ) {
             if ( algo ) 
                 print_hashline( md, algo, fname );
             else {
-                print_hashline( md, DIGEST_ALGO_MD5, fname );
-                print_hashline( md, DIGEST_ALGO_SHA1, fname );
-                print_hashline( md, DIGEST_ALGO_RMD160, fname );
-                if( !check_digest_algo(DIGEST_ALGO_TIGER) ) 
-                    print_hashline( md, DIGEST_ALGO_TIGER, fname );
+                print_hashline( md, GCRY_MD_MD5, fname );
+                print_hashline( md, GCRY_MD_SHA1, fname );
+                print_hashline( md, GCRY_MD_RMD160, fname );
+#ifdef USE_TIGER192
+               print_hashline( md, GCRY_MD_TIGER, fname );
+#endif
+#ifdef USE_SHA256
+                print_hashline( md, GCRY_MD_SHA256, fname );
+#endif
+#ifdef USE_SHA512
+               print_hashline( md, GCRY_MD_SHA384, fname );
+               print_hashline( md, GCRY_MD_SHA512, fname );
+#endif
             }
         }
         else {
-            if( algo ) {
-                if( fname )
-                    fputs( pname, stdout );
-                print_hex(md_read(md, algo), md_digest_length(algo) );
-            }
+            if( algo )
+              print_hex(md,-algo,fname);
             else {
-                printf(  "%s   MD5 = ", fname?pname:"" );
-                print_hex(md_read(md, DIGEST_ALGO_MD5), 16 );
-                printf("\n%s  SHA1 = ", fname?pname:""  );
-                print_hex(md_read(md, DIGEST_ALGO_SHA1), 20 );
-                printf("\n%sRMD160 = ", fname?pname:""  );
-                print_hex(md_read(md, DIGEST_ALGO_RMD160), 20 );
-                if( !check_digest_algo(DIGEST_ALGO_TIGER) ) {
-                    printf("\n%s TIGER = ", fname?pname:""  );
-                    print_hex(md_read(md, DIGEST_ALGO_TIGER), 24 );
-                }
+                print_hex( md, GCRY_MD_MD5, fname );
+                print_hex( md, GCRY_MD_SHA1, fname );
+                print_hex( md, GCRY_MD_RMD160, fname );
+#ifdef USE_TIGER192
+               print_hex( md, GCRY_MD_TIGER, fname );
+#endif
+#ifdef USE_SHA256
+                print_hex( md, GCRY_MD_SHA256, fname );
+#endif
+#ifdef USE_SHA512
+               print_hex( md, GCRY_MD_SHA384, fname );
+               print_hex( md, GCRY_MD_SHA512, fname );
+#endif
             }
-            putchar('\n');
         }
     }
-    md_close(md);
+    gcry_md_close (md);
 
     if( fp != stdin )
        fclose(fp);
@@ -2673,6 +3154,7 @@ add_notation_data( const char *string, int which )
     STRLIST sl,*notation_data;
     int critical=0;
     int highbit=0;
+    int saw_at=0;
 
     if(which)
       notation_data=&opt.cert_notation_data;
@@ -2684,13 +3166,29 @@ add_notation_data( const char *string, int which )
        string++;
     }
 
-    for( s=string ; *s != '='; s++ ) {
-       if( !*s || (*s & 0x80) || (!isgraph(*s) && !isspace(*s)) ) {
+    /* If and when the IETF assigns some official name tags, we'll
+       have to add them here. */
+
+    for( s=string ; *s != '='; s++ )
+      {
+       if( *s=='@')
+         saw_at=1;
+
+       if( !*s || (*s & 0x80) || (!isgraph(*s) && !isspace(*s)) )
+         {
            log_error(_("a notation name must have only printable characters "
                        "or spaces, and end with an '='\n") );
            return;
-       }
-    }
+         }
+      }
+
+    if(!saw_at && !opt.expert)
+      {
+       log_error(
+               _("a user notation name must contain the '@' character\n"));
+       return;
+      }
+
     /* we only support printable text - therefore we enforce the use
      * of only printable characters (an empty value is valid) */
     for( s++; *s ; s++ ) {