Imported Upstream version 2.1.13 upstream/2.1.13
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:10 +0000 (16:00 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:10 +0000 (16:00 +0900)
158 files changed:
NEWS
agent/agent.h
agent/command-ssh.c
agent/command.c
agent/findkey.c
agent/gpg-agent.c
agent/preset-passphrase.c
agent/protect-tool.c
agent/trustlist.c
autogen.sh
build-aux/getswdb.sh
build-aux/speedo.mk
build-aux/speedo/w32/inst.nsi
common/Makefile.am
common/asshelp.c
common/asshelp.h
common/call-gpg.c
common/ccparray.c [new file with mode: 0644]
common/ccparray.h [new file with mode: 0644]
common/exechelp-posix.c
common/exechelp-w32.c
common/exechelp-w32ce.c
common/exechelp.h
common/exectool.c
common/exectool.h
common/get-passphrase.c
common/get-passphrase.h
common/homedir.c
common/logging.c
common/openpgp-oid.c
common/openpgpdefs.h
common/status.h
common/stringhelp.c
common/stringhelp.h
common/sysutils.c
common/t-ccparray.c [new file with mode: 0644]
common/t-stringhelp.c
common/util.h
configure.ac
dirmngr/Makefile.am
dirmngr/dirmngr-client.c
dirmngr/dirmngr.c
dirmngr/dirmngr.h
dirmngr/dirmngr_ldap.c
dirmngr/http.c
dirmngr/ldap-wrapper.c
dirmngr/server.c
doc/DETAILS
doc/dirmngr.texi
doc/gnupg.texi
doc/gpg-agent.texi
doc/gpg.texi
doc/gpgsm.texi
doc/opt-homedir.texi
doc/scdaemon.texi
doc/sysnotes.texi
doc/tools.texi
doc/yat2m.c
g10/Makefile.am
g10/build-packet.c
g10/call-agent.c
g10/call-agent.h
g10/call-dirmngr.c
g10/delkey.c
g10/export.c
g10/free-packet.c
g10/getkey.c
g10/gpg.c
g10/gpg.h
g10/gpgcompose.c
g10/gpgsql.c [moved from g10/sqlite.c with 90% similarity]
g10/gpgsql.h [new file with mode: 0644]
g10/gpgv.c
g10/import.c
g10/keydb.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keyid.c
g10/keylist.c
g10/keyserver.c
g10/main.h
g10/mainproc.c
g10/migrate.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/photoid.c
g10/photoid.h
g10/pkclist.c
g10/progress.c
g10/revoke.c
g10/server.c
g10/seskey.c
g10/sig-check.c
g10/sign.c
g10/sqlite.h [deleted file]
g10/tdbio.c
g10/test-stubs.c
g10/tofu.c
g10/tofu.h
g10/trust.c
g10/trustdb.c
g10/trustdb.h
g13/be-encfs.c
g13/g13-common.h
g13/g13-syshelp.c
g13/g13.c
g13/server.c
kbx/keybox-defs.h
po/ca.po
po/cs.po
po/da.po
po/de.po
po/el.po
po/eo.po
po/es.po
po/et.po
po/fi.po
po/fr.po
po/gl.po
po/hu.po
po/id.po
po/it.po
po/ja.po
po/nb.po
po/pl.po
po/pt.po
po/ro.po
po/ru.po
po/sk.po
po/sv.po
po/tr.po
po/uk.po
po/zh_CN.po
po/zh_TW.po
scd/command.c
scd/scdaemon.c
scd/scdaemon.h
sm/call-agent.c
sm/call-dirmngr.c
sm/gpgsm.c
sm/gpgsm.h
sm/keydb.c
sm/server.c
tests/openpgp/Makefile.am
tests/openpgp/export.test [new file with mode: 0755]
tests/openpgp/fake-pinentry.c
tools/Makefile.am
tools/gpg-check-pattern.c
tools/gpg-connect-agent.c
tools/gpgconf-comp.c
tools/gpgconf.c
tools/gpgtar-create.c
tools/gpgtar-extract.c
tools/gpgtar-list.c
tools/rfc822parse.c
tools/symcryptrun.c

diff --git a/NEWS b/NEWS
index 4aa7a01..3c58883 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,53 @@
+Noteworthy changes in version 2.1.13 (2016-06-16)
+-------------------------------------------------
+
+ * gpg: New command --quick-addkey.  Extend the --quick-gen-key
+   command.
+
+ * gpg: New --keyid-format "none" which is now also the default.
+
+ * gpg: New option --with-subkey-fingerprint.
+
+ * gpg: Include Signer's UID subpacket in signatures if the secret key
+   has been specified using a mail address and the new option
+   --disable-signer-uid is not used.
+
+ * gpg: Allow unattended deletion of a secret key.
+
+ * gpg: Allow export of non-passphrase protected secret keys.
+
+ * gpg: New status lines KEY_CONSIDERED and NOTATION_FLAGS.
+
+ * gpg: Change status line TOFU_STATS_LONG to use '~' as
+   a non-breaking-space character.
+
+ * gpg: Speedup key listings in Tofu mode.
+
+ * gpg: Make sure that the current and total values of a PROGRESS
+   status line are small enough.
+
+ * gpgsm: Allow the use of AES192 and SERPENT ciphers.
+
+ * dirmngr: Adjust WKD lookup to current specs.
+
+ * dirmngr: Fallback to LDAP v3 if v2 is is not supported.
+
+ * gpgconf: New commands --create-socketdir and --remove-socketdir,
+   new option --homedir.
+
+ * If a /run/user/$UID directory exists, that directory is now used
+   for IPC sockets instead of the GNUPGHOME directory.  This fixes
+   problems with NFS and too long socket names and thus avoids the
+   need for redirection files.
+
+ * The Speedo build systems now uses the new versions.gnupg.org server
+   to retrieve the default package versions.
+
+ * Fix detection of libusb on FreeBSD.
+
+ * Speedup fd closing after a fork.
+
+
 Noteworthy changes in version 2.1.12 (2016-05-04)
 -------------------------------------------------
 
index 0dcb201..42a580c 100644 (file)
@@ -62,7 +62,6 @@ struct
   int quiet;           /* Be as quiet as possible */
   int dry_run;         /* Don't change any persistent data */
   int batch;           /* Batch mode */
-  const char *homedir; /* Configuration directory name */
 
   /* True if we handle sigusr2.  */
   int sigusr2_enabled;
index 0e1d9fc..e3cd4b9 100644 (file)
@@ -897,7 +897,7 @@ open_control_file (ssh_control_file_t *r_cf, int append)
   /* Note: As soon as we start to use non blocking functions here
      (i.e. where Pth might switch threads) we need to employ a
      mutex.  */
-  cf->fname = make_filename_try (opt.homedir, SSH_CONTROL_FILE_NAME, NULL);
+  cf->fname = make_filename_try (gnupg_homedir (), SSH_CONTROL_FILE_NAME, NULL);
   if (!cf->fname)
     {
       err = gpg_error_from_syserror ();
@@ -2734,7 +2734,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
   {
     char *dname;
 
-    dname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL);
+    dname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR, NULL);
     if (!dname)
       {
         err = gpg_err_code_from_syserror ();
index c94fdd3..de5b184 100644 (file)
@@ -207,7 +207,7 @@ clear_nonce_cache (ctrl_t ctrl)
 }
 
 
-/* This function is called by Libassuan whenever thee client sends a
+/* This function is called by Libassuan whenever the client sends a
    reset.  It has been registered similar to the other Assuan
    commands.  */
 static gpg_error_t
@@ -857,7 +857,8 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
 
 
 static const char hlp_genkey[] =
-  "GENKEY [--no-protection] [--preset] [--inq-passwd] [<cache_nonce>]\n"
+  "GENKEY [--no-protection] [--preset] [--inq-passwd]\n"
+  "       [--passwd-nonce=<s>] [<cache_nonce>]\n"
   "\n"
   "Generate a new key, store the secret part and return the public\n"
   "part.  Here is an example transaction:\n"
@@ -873,7 +874,8 @@ static const char hlp_genkey[] =
   "When the --preset option is used the passphrase for the generated\n"
   "key will be added to the cache.  When --inq-passwd is used an inquire\n"
   "with the keyword NEWPASSWD is used to request the passphrase for the\n"
-  "new key.\n";
+  "new key.  When a --passwd-nonce is used, the corresponding cached\n"
+  "passphrase is used to protect the new key.";
 static gpg_error_t
 cmd_genkey (assuan_context_t ctx, char *line)
 {
@@ -885,10 +887,12 @@ cmd_genkey (assuan_context_t ctx, char *line)
   unsigned char *newpasswd = NULL;
   membuf_t outbuf;
   char *cache_nonce = NULL;
+  char *passwd_nonce = NULL;
   int opt_preset;
   int opt_inq_passwd;
   size_t n;
-  char *p;
+  char *p, *pend;
+  int c;
 
   if (ctrl->restricted)
     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@@ -896,6 +900,21 @@ cmd_genkey (assuan_context_t ctx, char *line)
   no_protection = has_option (line, "--no-protection");
   opt_preset = has_option (line, "--preset");
   opt_inq_passwd = has_option (line, "--inq-passwd");
+  passwd_nonce = option_value (line, "--passwd-nonce");
+  if (passwd_nonce)
+    {
+      for (pend = passwd_nonce; *pend && !spacep (pend); pend++)
+        ;
+      c = *pend;
+      *pend = '\0';
+      passwd_nonce = xtrystrdup (passwd_nonce);
+      *pend = c;
+      if (!passwd_nonce)
+        {
+          rc = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
   line = skip_options (line);
 
   p = line;
@@ -933,6 +952,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
         }
 
     }
+  else if (passwd_nonce)
+    newpasswd = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
 
   rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
                      newpasswd, opt_preset, &outbuf);
@@ -951,6 +972,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
   else
     rc = write_and_clear_outbuf (ctx, &outbuf);
   xfree (cache_nonce);
+  xfree (passwd_nonce);
   return leave_cmd (ctx, rc);
 }
 
@@ -1236,7 +1258,8 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
       char *dirname;
       struct dirent *dir_entry;
 
-      dirname = make_filename_try (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL);
+      dirname = make_filename_try (gnupg_homedir (),
+                                   GNUPG_PRIVATE_KEYS_DIR, NULL);
       if (!dirname)
         {
           err = gpg_error_from_syserror ();
@@ -1715,6 +1738,24 @@ cmd_passwd (assuan_context_t ctx, char *line)
   else if (opt_verify)
     {
       /* All done.  */
+      if (passphrase)
+        {
+          if (!passwd_nonce)
+            {
+              char buf[12];
+              gcry_create_nonce (buf, 12);
+              passwd_nonce = bin2hex (buf, 12, NULL);
+            }
+          if (passwd_nonce
+              && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
+                                   passphrase, CACHE_TTL_NONCE))
+            {
+              assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
+              xfree (ctrl->server_local->last_passwd_nonce);
+              ctrl->server_local->last_passwd_nonce = passwd_nonce;
+              passwd_nonce = NULL;
+            }
+        }
     }
   else
     {
@@ -1785,6 +1826,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
   gcry_sexp_release (s_skey);
   xfree (shadow_info);
   xfree (cache_nonce);
+  xfree (passwd_nonce);
   return leave_cmd (ctx, err);
 }
 
@@ -2168,7 +2210,12 @@ static const char hlp_export_key[] =
   "Export a secret key from the key store.  The key will be encrypted\n"
   "using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
   "using the AESWRAP-128 algorithm.  The caller needs to retrieve that key\n"
-  "prior to using this command.  The function takes the keygrip as argument.\n";
+  "prior to using this command.  The function takes the keygrip as argument.\n"
+  "\n"
+  "If --openpgp is used, the secret key material will be exported in RFC 4880\n"
+  "compatible passphrase-protected form.  Without --openpgp, the secret key\n"
+  "material will be exported in the clear (after prompting the user to unlock\n"
+  "it, if needed).\n";
 static gpg_error_t
 cmd_export_key (assuan_context_t ctx, char *line)
 {
@@ -2333,8 +2380,9 @@ cmd_export_key (assuan_context_t ctx, char *line)
 static const char hlp_delete_key[] =
   "DELETE_KEY [--force] <hexstring_with_keygrip>\n"
   "\n"
-  "Delete a secret key from the key store.\n"
-  "Unless --force is used the agent asks the user for confirmation.\n";
+  "Delete a secret key from the key store.  If --force is used\n"
+  "and a loopback pinentry is allowed, the agent will not ask\n"
+  "the user for confirmation.";
 static gpg_error_t
 cmd_delete_key (assuan_context_t ctx, char *line)
 {
@@ -2349,6 +2397,11 @@ cmd_delete_key (assuan_context_t ctx, char *line)
   force = has_option (line, "--force");
   line = skip_options (line);
 
+  /* If the use of a loopback pinentry has been disabled, we assume
+   * that a silent deletion of keys shall also not be allowed.  */
+  if (!opt.allow_loopback_pinentry)
+    force = 0;
+
   err = parse_keygrip (ctx, line, grip);
   if (err)
     goto leave;
index a78709c..d3780b9 100644 (file)
@@ -135,7 +135,8 @@ agent_write_private_key (const unsigned char *grip,
   bin2hex (grip, 20, hexgrip);
   strcpy (hexgrip+40, ".key");
 
-  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
+  fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
+                         hexgrip, NULL);
 
   /* FIXME: Write to a temp file first so that write failures during
      key updates won't lead to a key loss.  */
@@ -652,7 +653,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
   bin2hex (grip, 20, hexgrip);
   strcpy (hexgrip+40, ".key");
 
-  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
+  fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
+                         hexgrip, NULL);
   fp = es_fopen (fname, "rb");
   if (!fp)
     {
@@ -767,7 +769,8 @@ remove_key_file (const unsigned char *grip)
 
   bin2hex (grip, 20, hexgrip);
   strcpy (hexgrip+40, ".key");
-  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
+  fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
+                         hexgrip, NULL);
   if (gnupg_remove (fname))
     err = gpg_error_from_syserror ();
   xfree (fname);
@@ -1289,7 +1292,8 @@ agent_key_available (const unsigned char *grip)
   bin2hex (grip, 20, hexgrip);
   strcpy (hexgrip+40, ".key");
 
-  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
+  fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
+                         hexgrip, NULL);
   result = !access (fname, R_OK)? 0 : -1;
   xfree (fname);
   return result;
index a950530..90b0eaf 100644 (file)
@@ -1,6 +1,6 @@
 /* gpg-agent.c  -  The GnuPG Agent
  * Copyright (C) 2000-2007, 2009-2010 Free Software Foundation, Inc.
- * Copyright (C) 2000-2014 Werner Koch
+ * Copyright (C) 2000-2016 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -555,19 +555,10 @@ remove_socket (char *name, char *redir_name)
 {
   if (name && *name)
     {
-      char *p;
-
       if (redir_name)
         name = redir_name;
 
       gnupg_remove (name);
-      p = strrchr (name, '/');
-      if (p)
-       {
-         *p = 0;
-         rmdir (name);
-         *p = '/';
-       }
       *name = 0;
     }
 }
@@ -804,8 +795,6 @@ main (int argc, char **argv )
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
 
-  opt.homedir = default_homedir ();
-
   /* Record some of the original environment strings. */
   {
     const char *s;
@@ -861,7 +850,7 @@ 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;
+          gnupg_set_homedir (pargs.r.ret_str);
        else if (pargs.r_opt == oDebugQuickRandom)
           {
             gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
@@ -878,8 +867,8 @@ main (int argc, char **argv )
   */
 
   if (default_config)
-    configname = make_filename (opt.homedir, GPG_AGENT_NAME EXTSEP_S "conf",
-                                NULL );
+    configname = make_filename (gnupg_homedir (),
+                                GPG_AGENT_NAME EXTSEP_S "conf", NULL);
 
   argc = orig_argc;
   argv = orig_argv;
@@ -944,7 +933,7 @@ main (int argc, char **argv )
         case oNoGreeting: /* Dummy option.  */ break;
         case oNoVerbose: opt.verbose = 0; break;
         case oNoOptions: break; /* no-options */
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oNoDetach: nodetach = 1; break;
         case oLogFile: logfile = pargs.r.ret_str; break;
         case oCsh: csh_style = 1; break;
@@ -1029,9 +1018,6 @@ main (int argc, char **argv )
 
   finalize_rereadable_options ();
 
-  /* Turn the homedir into an absolute one. */
-  opt.homedir = make_absfilename (opt.homedir, NULL);
-
   /* Print a warning if an argument looks like an option.  */
   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
     {
@@ -1104,8 +1090,8 @@ main (int argc, char **argv )
       char *filename_esc;
 
       /* List options and default values in the GPG Conf format.  */
-      filename = make_filename (opt.homedir, GPG_AGENT_NAME EXTSEP_S "conf",
-                                NULL );
+      filename = make_filename (gnupg_homedir (),
+                                GPG_AGENT_NAME EXTSEP_S "conf", NULL);
       filename_esc = percent_escape (filename, NULL);
 
       es_printf ("%s-%s.conf:%lu:\"%s\n",
@@ -1764,7 +1750,7 @@ create_socket_name (char *standard_name, int with_homedir)
   char *name;
 
   if (with_homedir)
-    name = make_filename (opt.homedir, standard_name, NULL);
+    name = make_filename (gnupg_socketdir (), standard_name, NULL);
   else
     name = make_filename (standard_name, NULL);
   if (strchr (name, PATHSEP_C))
@@ -1879,6 +1865,10 @@ create_server_socket (char *name, int primary, int cygwin,
       agent_exit (2);
     }
 
+  if (gnupg_chmod (unaddr->sun_path, "-rwx"))
+    log_error (_("can't set permissions of '%s': %s\n"),
+               unaddr->sun_path, strerror (errno));
+
   if (listen (FD2INT(fd), 5 ) == -1)
     {
       log_error (_("listen() failed: %s\n"), strerror (errno));
@@ -1932,7 +1922,7 @@ create_directories (void)
   const char *defhome = standard_homedir ();
   char *home;
 
-  home = make_filename (opt.homedir, NULL);
+  home = make_filename (gnupg_homedir (), NULL);
   if ( stat (home, &statbuf) )
     {
       if (errno == ENOENT)
@@ -2731,7 +2721,7 @@ check_own_socket (void)
   if (check_own_socket_running || shutdown_pending)
     return;  /* Still running or already shutting down.  */
 
-  sockname = make_filename (opt.homedir, GPG_AGENT_SOCK_NAME, NULL);
+  sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
   if (!sockname)
     return; /* Out of memory.  */
 
@@ -2757,7 +2747,9 @@ check_for_running_agent (int silent)
   char *sockname;
   assuan_context_t ctx = NULL;
 
-  sockname = make_filename (opt.homedir, GPG_AGENT_SOCK_NAME, NULL);
+  sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
+  if (!sockname)
+    return gpg_error_from_syserror ();
 
   err = assuan_new (&ctx);
   if (!err)
index 1ebf181..549ecc3 100644 (file)
@@ -66,7 +66,6 @@ enum cmd_and_opt_values
 aTest };
 
 
-static const char *opt_homedir;
 static const char *opt_passphrase;
 
 static ARGPARSE_OPTS opts[] = {
@@ -219,8 +218,6 @@ main (int argc, char **argv)
   i18n_init ();
   init_common_subsystems (&argc, &argv);
 
-  opt_homedir = default_homedir ();
-
   pargs.argc = &argc;
   pargs.argv = &argv;
   pargs.flags=  1;  /* (do not remove the args) */
@@ -229,7 +226,7 @@ main (int argc, char **argv)
       switch (pargs.r_opt)
         {
         case oVerbose: opt.verbose++; break;
-        case oHomedir: opt_homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
 
         case oPreset: cmd = oPreset; break;
         case oForget: cmd = oForget; break;
@@ -248,7 +245,7 @@ main (int argc, char **argv)
 
   /* Tell simple-pwquery about the the standard socket name.  */
   {
-    char *tmp = make_filename (opt_homedir, GPG_AGENT_SOCK_NAME, NULL);
+    char *tmp = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
     simple_pw_set_socket (tmp);
     xfree (tmp);
   }
index ad036ee..c2bf87d 100644 (file)
@@ -86,7 +86,6 @@ struct rsa_secret_key_s
 };
 
 
-static const char *opt_homedir;
 static int opt_armor;
 static int opt_canonical;
 static int opt_store;
@@ -577,9 +576,6 @@ main (int argc, char **argv )
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
 
 
-  opt_homedir = default_homedir ();
-
-
   pargs.argc = &argc;
   pargs.argv = &argv;
   pargs.flags=  1;  /* (do not remove the args) */
@@ -590,7 +586,7 @@ main (int argc, char **argv )
         case oVerbose: opt.verbose++; break;
         case oArmor:   opt_armor=1; break;
         case oCanonical: opt_canonical=1; break;
-        case oHomedir: opt_homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
 
         case oAgentProgram: opt_agent_program = pargs.r.ret_str; break;
 
@@ -634,7 +630,6 @@ main (int argc, char **argv )
   /* Set the information which can't be taken from envvars.  */
   gnupg_prepare_get_passphrase (GPG_ERR_SOURCE_DEFAULT,
                                 opt.verbose,
-                                opt_homedir,
                                 opt_agent_program,
                                 NULL, NULL, NULL);
 
index af5f645..b8df3fd 100644 (file)
@@ -344,7 +344,14 @@ read_trustfiles (void)
     return gpg_error_from_syserror ();
   tableidx = 0;
 
-  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
+  fname = make_filename_try (gnupg_homedir (), "trustlist.txt", NULL);
+  if (!fname)
+    {
+      err = gpg_error_from_syserror ();
+      xfree (table);
+      return err;
+    }
+
   if ( access (fname, F_OK) )
     {
       if ( errno == ENOENT )
@@ -608,7 +615,10 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
      trustlist with only admin priviliges to modify it.  Of course
      this is not a secure way of denying access, but it avoids the
      usual clicking on an Okay button most users are used to. */
-  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
+  fname = make_filename_try (gnupg_homedir (), "trustlist.txt", NULL);
+  if (!fname)
+    return gpg_error_from_syserror ();
+
   if ( access (fname, W_OK) && errno != ENOENT)
     {
       xfree (fname);
@@ -733,7 +743,15 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
       return is_disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0;
     }
 
-  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
+  fname = make_filename_try (gnupg_homedir (), "trustlist.txt", NULL);
+  if (!fname)
+    {
+      err = gpg_error_from_syserror ();
+      unlock_trusttable ();
+      xfree (fprformatted);
+      xfree (nameformatted);
+      return err;
+    }
   if ( access (fname, F_OK) && errno == ENOENT)
     {
       fp = es_fopen (fname, "wx,mode=-rw-r");
index 7d843bd..10cc203 100755 (executable)
@@ -423,7 +423,7 @@ if [ -d .git ]; then
     [ -z "${SILENT}" ] && cat <<EOF
 *** Activating trailing whitespace git pre-commit hook. ***
     For more information see this thread:
-      http://mail.gnome.org/archives/desktop-devel-list/2009-May/msg00084html
+      http://mail.gnome.org/archives/desktop-devel-list/2009-May/msg00084.html
     To deactivate this pre-commit hook again move .git/hooks/pre-commit
     and .git/hooks/pre-commit.sample out of the way.
 EOF
index 4a1730b..83ecdb2 100755 (executable)
@@ -11,9 +11,7 @@
 # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 # The URL of the file to retrieve.
-# (some wget versions seem to have problems with SubjectAltName, thus
-#  we do not use www.gnupg.org)
-urlbase="https://gnupg.org/"
+urlbase="https://versions.gnupg.org/"
 
 WGET=wget
 GPGV=gpgv
index d286655..67ccbb4 100644 (file)
@@ -448,7 +448,9 @@ speedo_pkg_libgcrypt_configure = --disable-static
 speedo_pkg_libksba_configure = --disable-static
 
 ifeq ($(TARGETOS),w32)
-speedo_pkg_gnupg_configure = --enable-gpg2-is-gpg --disable-g13 --disable-ntbtls
+speedo_pkg_gnupg_configure = \
+        --enable-gpg2-is-gpg --disable-g13 --disable-ntbtls \
+        --enable-build-timestamp
 else
 speedo_pkg_gnupg_configure = --disable-g13
 endif
index 2c671c2..24d5d4d 100644 (file)
@@ -579,6 +579,7 @@ Section "GnuPG" SEC_gnupg
   File "bin/gpgconf.exe"
   File "bin/gpg-connect-agent.exe"
   File "bin/gpgtar.exe"
+  File "libexec/gpg-preset-passphrase.exe"
 
   ClearErrors
   SetOverwrite try
@@ -1275,6 +1276,7 @@ Section "-un.gnupg"
   Delete "$INSTDIR\bin\gpgconf.exe"
   Delete "$INSTDIR\bin\gpg-connect-agent.exe"
   Delete "$INSTDIR\bin\gpgtar.exe"
+  Delete "$INSTDIR\bin\gpg-preset-passphrase.exe"
 
   Delete "$INSTDIR\share\gnupg\dirmngr-conf.skel"
   Delete "$INSTDIR\share\gnupg\distsigkey.gpg"
index 4a35f64..884c966 100644 (file)
@@ -72,6 +72,7 @@ common_sources = \
        xasprintf.c \
        xreadline.c \
        membuf.c membuf.h \
+       ccparray.c ccparray.h \
        iobuf.c iobuf.h \
        ttyio.c ttyio.h \
        asshelp.c asshelp2.c asshelp.h \
@@ -156,7 +157,7 @@ module_tests = t-stringhelp t-timestuff \
                t-convert t-percent t-gettime t-sysutils t-sexputil \
               t-session-env t-openpgp-oid t-ssh-utils \
               t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
-              t-private-keys
+              t-private-keys t-ccparray
 if !HAVE_W32CE_SYSTEM
 module_tests += t-exechelp
 endif
@@ -206,6 +207,7 @@ t_mbox_util_LDADD = $(t_common_ldadd)
 t_iobuf_LDADD = $(t_common_ldadd)
 t_strlist_LDADD = $(t_common_ldadd)
 t_private_keys_LDADD = $(t_common_ldadd)
+t_ccparray_LDADD = $(t_common_ldadd)
 
 # System specific test
 if HAVE_W32_SYSTEM
index f2b4402..5c32c6e 100644 (file)
@@ -351,7 +351,6 @@ unlock_spawning (lock_spawn_t *lock, const char *name)
 gpg_error_t
 start_new_gpg_agent (assuan_context_t *r_ctx,
                      gpg_err_source_t errsource,
-                     const char *homedir,
                      const char *agent_program,
                      const char *opt_lc_ctype,
                      const char *opt_lc_messages,
@@ -375,7 +374,14 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
       return err;
     }
 
-  sockname = make_absfilename (homedir, GPG_AGENT_SOCK_NAME, NULL);
+  sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
+  if (!sockname)
+    {
+      err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+      assuan_release (ctx);
+      return err;
+    }
+
   err = assuan_socket_connect (ctx, sockname, 0, 0);
   if (err && autostart)
     {
@@ -418,7 +424,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
       /* We better pass an absolute home directory to the agent just
          in case gpg-agent does not convert the passed name to an
          absolute one (which it should do).  */
-      abs_homedir = make_absfilename_try (homedir, NULL);
+      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
       if (!abs_homedir)
         {
           gpg_error_t tmperr = gpg_err_make (errsource,
@@ -455,7 +461,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
       argv[i++] = "--daemon";
       argv[i++] = NULL;
 
-      if (!(err = lock_spawning (&lock, homedir, "agent", verbose))
+      if (!(err = lock_spawning (&lock, gnupg_homedir (), "agent", verbose))
           && assuan_socket_connect (ctx, sockname, 0, 0))
         {
           err = gnupg_spawn_process_detached (program? program : agent_program,
@@ -538,7 +544,6 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
 gpg_error_t
 start_new_dirmngr (assuan_context_t *r_ctx,
                    gpg_err_source_t errsource,
-                   const char *homedir,
                    const char *dirmngr_program,
                    int autostart,
                    int verbose, int debug,
@@ -605,7 +610,7 @@ start_new_dirmngr (assuan_context_t *r_ctx,
         status_cb (status_cb_arg, STATUS_PROGRESS,
                    "starting_dirmngr ? 0 0", NULL);
 
-      abs_homedir = make_absfilename (homedir, NULL);
+      abs_homedir = make_absfilename (gnupg_homedir (), NULL);
       if (!abs_homedir)
         {
           gpg_error_t tmperr = gpg_err_make (errsource,
@@ -641,7 +646,7 @@ start_new_dirmngr (assuan_context_t *r_ctx,
          TRY_SYSTEM_DAEMON should never be true because
          dirmngr_user_socket_name() won't return NULL.  */
 
-      if (!(err = lock_spawning (&lock, homedir, "dirmngr", verbose))
+      if (!(err = lock_spawning (&lock, gnupg_homedir (), "dirmngr", verbose))
           && assuan_socket_connect (ctx, sockname, 0, 0))
         {
           err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL);
@@ -678,7 +683,6 @@ start_new_dirmngr (assuan_context_t *r_ctx,
       xfree (abs_homedir);
     }
 #else
-  (void)homedir;
   (void)dirmngr_program;
   (void)verbose;
   (void)status_cb;
index 20414bd..4eb1d92 100644 (file)
@@ -54,7 +54,6 @@ send_pinentry_environment (assuan_context_t ctx,
 gpg_error_t
 start_new_gpg_agent (assuan_context_t *r_ctx,
                      gpg_err_source_t errsource,
-                     const char *homedir,
                      const char *agent_program,
                      const char *opt_lc_ctype,
                      const char *opt_lc_messages,
@@ -68,7 +67,6 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
 gpg_error_t
 start_new_dirmngr (assuan_context_t *r_ctx,
                    gpg_err_source_t errsource,
-                   const char *homedir,
                    const char *dirmngr_program,
                    int autostart, int verbose, int debug,
                    gpg_error_t (*status_cb)(ctrl_t, int, ...),
index f5a62ec..0bda1d3 100644 (file)
@@ -430,9 +430,9 @@ _gpg_encrypt (ctrl_t ctrl,
   assert ((reader_mb == NULL) != (cipher_stream == NULL));
 
   /* Create two pipes.  */
-  err = gnupg_create_outbound_pipe (outbound_fds);
+  err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0);
   if (!err)
-    err = gnupg_create_inbound_pipe (inbound_fds);
+    err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0);
   if (err)
     {
       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
@@ -614,9 +614,9 @@ _gpg_decrypt (ctrl_t ctrl,
   assert ((reader_mb == NULL) != (plain_stream == NULL));
 
   /* Create two pipes.  */
-  err = gnupg_create_outbound_pipe (outbound_fds);
+  err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0);
   if (!err)
-    err = gnupg_create_inbound_pipe (inbound_fds);
+    err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0);
   if (err)
     {
       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
diff --git a/common/ccparray.c b/common/ccparray.c
new file mode 100644 (file)
index 0000000..490dbf5
--- /dev/null
@@ -0,0 +1,147 @@
+/* ccparray.c - A simple dynamic array for character pointer.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "util.h"
+#include "ccparray.h"
+
+
+/* A simple implementation of a dynamic array of const char pointers.
+ * The example code:
+ *
+ *   ccparray_t ccp;
+ *   const char **argv;
+ *   int i;
+ *
+ *   ccparray_init (&ccp, 0);
+ *   ccparray_put (&ccp, "First arg");
+ *   ccparray_put (&ccp, "Second arg");
+ *   ccparray_put (&ccp, NULL);
+ *   ccparray_put (&ccp, "Fourth arg");
+ *   argv = ccparray_get (&ccp, NULL);
+ *   if (!argv)
+ *     die ("error building array: %s\n", strerror (errno));
+ *   for (i=0; argv[i]; i++)
+ *     printf ("[%d] = '%s'\n", i, argv[i]);
+ *   xfree (argv);
+ *
+ * will result in this output:
+ *
+ *   [0] = 'First arg'
+ *   [1] = 'Second arg'
+ *
+ * Note that allocation errors are detected but only returned with the
+ * final ccparray_get(); this helps not to clutter the code with out
+ * of core checks.
+ */
+
+void
+ccparray_init (ccparray_t *cpa, unsigned int initialsize)
+{
+  if (!initialsize)
+    cpa->size = 16;
+  else if (initialsize < (1<<16))
+    cpa->size = initialsize;
+  else
+    cpa->size = (1<<16);
+
+  cpa->count = 0;
+  cpa->out_of_core = 0;
+  cpa->array = xtrycalloc (cpa->size, sizeof *cpa->array);
+  if (!cpa->array)
+    cpa->out_of_core = errno;
+}
+
+
+void
+ccparray_put (ccparray_t *cpa, const char *value)
+{
+  if (cpa->out_of_core)
+    return;
+
+  if (cpa->count + 1 >= cpa->size)
+    {
+      const char **newarray;
+      size_t n, newsize;
+
+      if (cpa->size < 8)
+        newsize = 16;
+      else if (cpa->size < 4096)
+        newsize = 2 * cpa->size;
+      else if (cpa->size < (1<<16))
+        newsize = cpa->size + 2048;
+      else
+        {
+          cpa->out_of_core = ENOMEM;
+          return;
+        }
+
+      newarray = xtrycalloc (newsize, sizeof *newarray);
+      if (!newarray)
+        {
+          cpa->out_of_core = errno ? errno : ENOMEM;
+          return;
+        }
+      for (n=0; n < cpa->size; n++)
+        newarray[n] = cpa->array[n];
+      cpa->array = newarray;
+      cpa->size = newsize;
+
+    }
+  cpa->array[cpa->count++] = value;
+}
+
+
+const char **
+ccparray_get (ccparray_t *cpa, size_t *r_count)
+{
+  const char **result;
+
+  if (cpa->out_of_core)
+    {
+      if (cpa->array)
+        {
+          xfree (cpa->array);
+          cpa->array = NULL;
+        }
+      gpg_err_set_errno (cpa->out_of_core);
+      return NULL;
+    }
+
+  result= cpa->array;
+  if (r_count)
+    *r_count = cpa->count;
+  cpa->array = NULL;
+  cpa->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
+  return result;
+}
diff --git a/common/ccparray.h b/common/ccparray.h
new file mode 100644 (file)
index 0000000..241d42d
--- /dev/null
@@ -0,0 +1,51 @@
+/* ccparray.c - A simple dynamic array for character pointer.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_CCPARRAY_H
+#define GNUPG_COMMON_CCPARRAY_H
+
+/* The definition of the structure is private, we only need it here,
+ * so it can be allocated on the stack.  */
+struct _ccparray_private_s
+{
+  unsigned int count;
+  unsigned int size;
+  int out_of_core;
+  const char **array;
+};
+
+typedef struct _ccparray_private_s ccparray_t;
+
+
+void ccparray_init (ccparray_t *cpa, unsigned int initialsize);
+void ccparray_put (ccparray_t *cpa, const char *value);
+const char **ccparray_get (ccparray_t *cpa, size_t *r_nelems);
+
+
+#endif /*GNUPG_COMMON_CCPARRAY_H*/
index 6614eb7..aefb653 100644 (file)
 # include <sys/stat.h>
 #endif
 
+#if __linux__
+# include <sys/types.h>
+# include <dirent.h>
+#endif /*__linux__ */
+
 #include "util.h"
 #include "i18n.h"
 #include "sysutils.h"
 #include "exechelp.h"
 
 
+/* Helper */
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+  return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+static inline gpg_error_t
+my_error (int errcode)
+{
+  return gpg_err_make (default_errsource, errcode);
+}
+
+
 /* Return the maximum number of currently allowed open file
    descriptors.  Only useful on POSIX systems but returns a value on
    other systems too.  */
@@ -83,6 +102,43 @@ get_max_fds (void)
 #ifdef HAVE_GETRLIMIT
   struct rlimit rl;
 
+  /* Under Linux we can figure out the highest used file descriptor by
+   * reading /proc/PID/fd.  This is in the common cases much fast than
+   * for example doing 4096 close calls where almost all of them will
+   * fail.  On a system with a limit of 4096 files and only 8 files
+   * open with the highest number being 10, we speedup close_all_fds
+   * from 125ms to 0.4ms including readdir.
+   *
+   * Another option would be to close the file descriptors as returned
+   * from reading that directory - however then we need to snapshot
+   * that list before starting to close them.  */
+#ifdef __linux__
+  {
+    DIR *dir = NULL;
+    struct dirent *dir_entry;
+    const char *s;
+    int x;
+
+    dir = opendir ("/proc/self/fd");
+    if (dir)
+      {
+        while ((dir_entry = readdir (dir)))
+          {
+            s = dir_entry->d_name;
+            if ( *s < '0' || *s > '9')
+              continue;
+            x = atoi (s);
+            if (x > max_fds)
+              max_fds = x;
+          }
+        closedir (dir);
+      }
+    if (max_fds != -1)
+      return max_fds + 1;
+    }
+#endif /* __linux__ */
+
+
 # ifdef RLIMIT_NOFILE
   if (!getrlimit (RLIMIT_NOFILE, &rl))
     max_fds = rl.rlim_max;
@@ -222,7 +278,7 @@ get_all_open_fds (void)
 static void
 do_exec (const char *pgmname, const char *argv[],
          int fd_in, int fd_out, int fd_err,
-         void (*preexec)(void) )
+         int *except, void (*preexec)(void) )
 {
   char **arg_list;
   int i, j;
@@ -268,7 +324,7 @@ do_exec (const char *pgmname, const char *argv[],
     }
 
   /* Close all other files. */
-  close_all_fds (3, NULL);
+  close_all_fds (3, except);
 
   if (preexec)
     preexec ();
@@ -285,64 +341,36 @@ do_create_pipe (int filedes[2])
 
   if (pipe (filedes) == -1)
     {
-      err = gpg_error_from_syserror ();
+      err = my_error_from_syserror ();
       filedes[0] = filedes[1] = -1;
     }
 
   return err;
 }
 
-/* Portable function to create a pipe.  Under Windows the write end is
-   inheritable.  */
-gpg_error_t
-gnupg_create_inbound_pipe (int filedes[2])
-{
-  return do_create_pipe (filedes);
-}
-
-
-/* Portable function to create a pipe.  Under Windows the read end is
-   inheritable.  */
-gpg_error_t
-gnupg_create_outbound_pipe (int filedes[2])
-{
-  return do_create_pipe (filedes);
-}
-
-
-/* Portable function to create a pipe.  Under Windows both ends are
-   inheritable.  */
-gpg_error_t
-gnupg_create_pipe (int filedes[2])
-{
-  return do_create_pipe (filedes);
-}
-
-
 
 static gpg_error_t
 create_pipe_and_estream (int filedes[2], estream_t *r_fp,
-                         int outbound, int nonblock,
-                         gpg_err_source_t errsource)
+                         int outbound, int nonblock)
 {
   gpg_error_t err;
 
   if (pipe (filedes) == -1)
     {
-      err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+      err = my_error_from_syserror ();
       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
       filedes[0] = filedes[1] = -1;
       *r_fp = NULL;
       return err;
     }
 
-  if (outbound)
+  if (!outbound)
     *r_fp = es_fdopen (filedes[0], nonblock? "r,nonblock" : "r");
   else
     *r_fp = es_fdopen (filedes[1], nonblock? "w,nonblock" : "w");
   if (!*r_fp)
     {
-      err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+      err = my_error_from_syserror ();
       log_error (_("error creating a stream for a pipe: %s\n"),
                  gpg_strerror (err));
       close (filedes[0]);
@@ -354,12 +382,45 @@ create_pipe_and_estream (int filedes[2], estream_t *r_fp,
 }
 
 
+/* Portable function to create a pipe.  Under Windows the write end is
+   inheritable.  If R_FP is not NULL, an estream is created for the
+   read end and stored at R_FP.  */
+gpg_error_t
+gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+  if (r_fp)
+    return create_pipe_and_estream (filedes, r_fp, 0, nonblock);
+  else
+    return do_create_pipe (filedes);
+}
+
+
+/* Portable function to create a pipe.  Under Windows the read end is
+   inheritable.  If R_FP is not NULL, an estream is created for the
+   write end and stored at R_FP.  */
+gpg_error_t
+gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+  if (r_fp)
+    return create_pipe_and_estream (filedes, r_fp, 1, nonblock);
+  else
+    return do_create_pipe (filedes);
+}
+
+
+/* Portable function to create a pipe.  Under Windows both ends are
+   inheritable.  */
+gpg_error_t
+gnupg_create_pipe (int filedes[2])
+{
+  return do_create_pipe (filedes);
+}
+
 
 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     gpg_err_source_t errsource,
-                     void (*preexec)(void), unsigned int flags,
+                     int *except, void (*preexec)(void), unsigned int flags,
                      estream_t *r_infp,
                      estream_t *r_outfp,
                      estream_t *r_errfp,
@@ -384,14 +445,14 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
 
   if (r_infp)
     {
-      err = create_pipe_and_estream (inpipe, &infp, 0, nonblock, errsource);
+      err = create_pipe_and_estream (inpipe, &infp, 1, nonblock);
       if (err)
         return err;
     }
 
   if (r_outfp)
     {
-      err = create_pipe_and_estream (outpipe, &outfp, 1, nonblock, errsource);
+      err = create_pipe_and_estream (outpipe, &outfp, 0, nonblock);
       if (err)
         {
           if (infp)
@@ -407,7 +468,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
 
   if (r_errfp)
     {
-      err = create_pipe_and_estream (errpipe, &errfp, 1, nonblock, errsource);
+      err = create_pipe_and_estream (errpipe, &errfp, 0, nonblock);
       if (err)
         {
           if (infp)
@@ -432,7 +493,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
   *pid = fork ();
   if (*pid == (pid_t)(-1))
     {
-      err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+      err = my_error_from_syserror ();
       log_error (_("error forking process: %s\n"), gpg_strerror (err));
 
       if (infp)
@@ -464,7 +525,8 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
       gcry_control (GCRYCTL_TERM_SECMEM);
       es_fclose (outfp);
       es_fclose (errfp);
-      do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1], preexec);
+      do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1],
+               except, preexec);
       /*NOTREACHED*/
     }
 
@@ -505,7 +567,7 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
   *pid = fork ();
   if (*pid == (pid_t)(-1))
     {
-      err = gpg_error_from_syserror ();
+      err = my_error_from_syserror ();
       log_error (_("error forking process: %s\n"), strerror (errno));
       return err;
     }
@@ -514,7 +576,7 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
     {
       gcry_control (GCRYCTL_TERM_SECMEM);
       /* Run child. */
-      do_exec (pgmname, argv, infd, outfd, errfd, NULL);
+      do_exec (pgmname, argv, infd, outfd, errfd, NULL, NULL);
       /*NOTREACHED*/
     }
 
@@ -543,7 +605,7 @@ gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
         r_exitcodes[i] = -1;
 
       if (pids[i] == (pid_t)(-1))
-        return gpg_error (GPG_ERR_INV_VALUE);
+        return my_error (GPG_ERR_INV_VALUE);
     }
 
   left = count;
@@ -638,16 +700,16 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
   int i;
 
   if (getuid() != geteuid())
-    return gpg_error (GPG_ERR_BUG);
+    return my_error (GPG_ERR_BUG);
 
   if (access (pgmname, X_OK))
-    return gpg_error_from_syserror ();
+    return my_error_from_syserror ();
 
   pid = fork ();
   if (pid == (pid_t)(-1))
     {
       log_error (_("error forking process: %s\n"), strerror (errno));
-      return gpg_error_from_syserror ();
+      return my_error_from_syserror ();
     }
   if (!pid)
     {
@@ -667,7 +729,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
         for (i=0; envp[i]; i++)
           putenv (xstrdup (envp[i]));
 
-      do_exec (pgmname, argv, -1, -1, -1, NULL);
+      do_exec (pgmname, argv, -1, -1, -1, NULL, NULL);
 
       /*NOTREACHED*/
     }
index 3e407d2..b2d2457 100644 (file)
@@ -320,20 +320,28 @@ do_create_pipe (int filedes[2], int flags)
 }
 
 /* Portable function to create a pipe.  Under Windows the write end is
-   inheritable.  */
+   inheritable.  If R_FP is not NULL, an estream is created for the
+   read end and stored at R_FP.  */
 gpg_error_t
-gnupg_create_inbound_pipe (int filedes[2])
+gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
 {
-  return do_create_pipe (filedes, INHERIT_WRITE);
+  if (r_fp)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  else
+    return do_create_pipe (filedes, INHERIT_WRITE);
 }
 
 
 /* Portable function to create a pipe.  Under Windows the read end is
-   inheritable.  */
+   inheritable.  If R_FP is not NULL, an estream is created for the
+   write end and stored at R_FP.  */
 gpg_error_t
-gnupg_create_outbound_pipe (int filedes[2])
+gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
 {
-  return do_create_pipe (filedes, INHERIT_READ);
+  if (r_fp)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  else
+    return do_create_pipe (filedes, INHERIT_READ);
 }
 
 
@@ -349,8 +357,7 @@ gnupg_create_pipe (int filedes[2])
 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     gpg_err_source_t errsource,
-                     void (*preexec)(void), unsigned int flags,
+                     int *except, void (*preexec)(void), unsigned int flags,
                      estream_t *r_infp,
                      estream_t *r_outfp,
                      estream_t *r_errfp,
@@ -379,6 +386,9 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
                       INVALID_HANDLE_VALUE};
   int i;
   es_syshd_t syshd;
+  gpg_err_source_t errsource = default_errsource;
+
+  (void)except; /* Not yet used.  */
 
   if (r_infp)
     *r_infp = NULL;
index e208f6e..9e72cef 100644 (file)
@@ -450,18 +450,24 @@ create_inheritable_pipe (int filedes[2], int inherit_idx)
 /* Portable function to create a pipe.  Under Windows the write end is
    inheritable (i.e. an rendezvous id).  */
 gpg_error_t
-gnupg_create_inbound_pipe (int filedes[2])
+gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
 {
-  return create_inheritable_pipe (filedes, 1);
+  if (r_fp)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  else
+    return create_inheritable_pipe (filedes, 1);
 }
 
 
 /* Portable function to create a pipe.  Under Windows the read end is
    inheritable (i.e. an rendezvous id).  */
 gpg_error_t
-gnupg_create_outbound_pipe (int filedes[2])
+gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
 {
-  return create_inheritable_pipe (filedes, 0);
+  if (r_fp)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  else
+    return create_inheritable_pipe (filedes, 0);
 }
 
 
@@ -509,8 +515,7 @@ create_process (const char *pgmname, const char *cmdline,
 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     gpg_err_source_t errsource,
-                     void (*preexec)(void), unsigned int flags,
+                     int *except, void (*preexec)(void), unsigned int flags,
                      estream_t *r_infp,
                      estream_t *r_outfp,
                      estream_t *r_errfp,
@@ -534,7 +539,9 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
   } errpipe = {INVALID_HANDLE_VALUE, 0};
   estream_t outfp = NULL;
   estream_t errfp = NULL;
+  gpg_err_source_t errsource = default_errsource;
 
+  (void)except; /* Not yet used.  */
   (void)preexec;
   (void)flags;
 
index 82224fd..c43cd25 100644 (file)
@@ -52,12 +52,16 @@ int *get_all_open_fds (void);
 
 
 /* Portable function to create a pipe.  Under Windows the write end is
-   inheritable.  */
-gpg_error_t gnupg_create_inbound_pipe (int filedes[2]);
+   inheritable.  If R_FP is not NULL, an estream is created for the
+   write end and stored at R_FP.  */
+gpg_error_t gnupg_create_inbound_pipe (int filedes[2],
+                                       estream_t *r_fp, int nonblock);
 
 /* Portable function to create a pipe.  Under Windows the read end is
-   inheritable.  */
-gpg_error_t gnupg_create_outbound_pipe (int filedes[2]);
+   inheritable.  If R_FP is not NULL, an estream is created for the
+   write end and stored at R_FP.  */
+gpg_error_t gnupg_create_outbound_pipe (int filedes[2],
+                                        estream_t *r_fp, int nonblock);
 
 /* Portable function to create a pipe.  Under Windows both ends are
    inheritable.  */
@@ -86,6 +90,10 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
    If PREEXEC is not NULL, the given function will be called right
    before the exec.
 
+   IF EXCEPT is not NULL, it is expected to be an ordered list of file
+   descriptors, terminated by an entry with the value (-1).  These
+   file descriptors won't be closed before spawning a new program.
+
    Returns 0 on success or an error code.  Calling gnupg_wait_process
    and gnupg_release_process is required if the function succeeded.
 
@@ -112,8 +120,7 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     gpg_err_source_t errsource,
-                     void (*preexec)(void), unsigned int flags,
+                     int *execpt, void (*preexec)(void), unsigned int flags,
                      estream_t *r_infp,
                      estream_t *r_outfp,
                      estream_t *r_errfp,
index 7b3a8f1..897450e 100644 (file)
 #include "exechelp.h"
 #include "sysutils.h"
 #include "util.h"
+#include "exectool.h"
 
 typedef struct
 {
   const char *pgmname;
+  exec_tool_status_cb_t status_cb;
+  void *status_cb_value;
   int cont;
-  int used;
-  char buffer[256];
+  size_t used;
+  size_t buffer_size;
+  char *buffer;
 } read_and_log_buffer_t;
 
 
@@ -83,14 +87,37 @@ read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
             pname++;
           else
             pname = state->pgmname;
-          /* If our pgmname plus colon is identical to the start of
-             the output, print only the output.  */
           len = strlen (pname);
-          if (!state->cont
+
+          if (state->status_cb
+              && !strncmp (state->buffer, "[GNUPG:] ", 9)
+              && state->buffer[9] >= 'A' && state->buffer[9] <= 'Z')
+            {
+              char *rest;
+
+              rest = strchr (state->buffer + 9, ' ');
+              if (!rest)
+                {
+                  /* Set REST to an empty string.  */
+                  rest = state->buffer + strlen (state->buffer);
+                }
+              else
+                {
+                  *rest++ = 0;
+                  trim_spaces (rest);
+                }
+              state->status_cb (state->status_cb_value,
+                                state->buffer + 9, rest);
+            }
+          else if (!state->cont
               && !strncmp (state->buffer, pname, len)
               && strlen (state->buffer) > strlen (pname)
               && state->buffer[len] == ':' )
-            log_info ("%s\n", state->buffer);
+            {
+              /* PGMNAME plus colon is identical to the start of
+                 the output: print only the output.  */
+              log_info ("%s\n", state->buffer);
+            }
           else
             log_info ("%s%c %s\n",
                       pname, state->cont? '+':':', state->buffer);
@@ -123,10 +150,39 @@ read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
         }
       else
         {
-          if (state->used >= sizeof state->buffer - 1)
+          if (state->used >= state->buffer_size - 1)
             {
-              read_and_log_stderr (state, NULL);
-              state->cont = 1;
+              if (state->status_cb)
+                {
+                  /* A status callback requires that we have a full
+                   * line.  Thus we need to enlarget the buffer in
+                   * this case.  */
+                  char *newbuffer;
+                  size_t newsize = state->buffer_size + 256;
+
+                  newbuffer = xtrymalloc (newsize);
+                  if (!newbuffer)
+                    {
+                      log_error ("error allocating memory for status cb: %s\n",
+                                 gpg_strerror (my_error_from_syserror ()));
+                      /* We better disable the status CB in this case.  */
+                      state->status_cb = NULL;
+                      read_and_log_stderr (state, NULL);
+                      state->cont = 1;
+                    }
+                  else
+                    {
+                      memcpy (newbuffer, state->buffer, state->used);
+                      xfree (state->buffer);
+                      state->buffer = newbuffer;
+                      state->buffer_size = newsize;
+                    }
+                }
+              else
+                {
+                  read_and_log_stderr (state, NULL);
+                  state->cont = 1;
+                }
             }
           state->buffer[state->used++] = c;
         }
@@ -188,7 +244,8 @@ copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
   if (c->nread == 0)
     return 0;  /* Done copying.  */
 
-  err = es_write (sink, c->writep, c->nread, &nwritten);
+
+  err = sink? es_write (sink, c->writep, c->nread, &nwritten) : 0;
   if (err)
     {
       if (errno == EAGAIN)
@@ -202,7 +259,7 @@ copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
   c->nread -= nwritten;
   assert (c->writep - c->buffer <= sizeof c->buffer);
 
-  if (es_fflush (sink) && errno != EAGAIN)
+  if (sink && es_fflush (sink) && errno != EAGAIN)
     err = my_error_from_syserror ();
 
   return err;
@@ -228,41 +285,95 @@ copy_buffer_flush (struct copy_buffer *c, estream_t sink)
 \f
 
 /* Run the program PGMNAME with the command line arguments given in
-   the NULL terminates array ARGV.  If INPUT is not NULL it will be
-   fed to stdin of the process.  stderr is logged using log_info and
-   the process' stdout is written to OUTPUT.  On error a diagnostic is
-   printed, and an error code returned.  */
+ * the NULL terminates array ARGV.  If INPUT is not NULL it will be
+ * fed to stdin of the process.  stderr is logged using log_info and
+ * the process' stdout is written to OUTPUT.  If OUTPUT is NULL the
+ * output is discarded.  If INEXTRA is given, an additional input
+ * stream will be passed to the child; to tell the child about this
+ * ARGV is scanned and the first occurrence of an argument
+ * "-&@INEXTRA@" is replaced by the concatenation of "-&" and the
+ * child's file descriptor of the pipe created for the INEXTRA stream.
+ *
+ * On error a diagnostic is printed and an error code returned.  */
 gpg_error_t
 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
-                        estream_t input,
-                        estream_t output)
+                        estream_t input, estream_t inextra,
+                        estream_t output,
+                        exec_tool_status_cb_t status_cb,
+                        void *status_cb_value)
 {
   gpg_error_t err;
   pid_t pid;
   estream_t infp = NULL;
+  estream_t extrafp = NULL;
   estream_t outfp, errfp;
-  es_poll_t fds[3];
+  es_poll_t fds[4];
+  int exceptclose[2];
+  int extrapipe[2] = {-1, -1};
+  char extrafdbuf[20];
+  const char *argsave = NULL;
+  int argsaveidx;
   int count;
   read_and_log_buffer_t fderrstate;
-  struct copy_buffer cpbuf[2];
+  struct copy_buffer cpbuf_in, cpbuf_out, cpbuf_extra; /* Fixme: malloc them. */
 
   memset (fds, 0, sizeof fds);
   memset (&fderrstate, 0, sizeof fderrstate);
-  copy_buffer_init (&cpbuf[0]);
-  copy_buffer_init (&cpbuf[1]);
+  copy_buffer_init (&cpbuf_in);
+  copy_buffer_init (&cpbuf_out);
+  copy_buffer_init (&cpbuf_extra);
+
+  fderrstate.pgmname = pgmname;
+  fderrstate.status_cb = status_cb;
+  fderrstate.status_cb_value = status_cb_value;
+  fderrstate.buffer_size = 256;
+  fderrstate.buffer = xtrymalloc (fderrstate.buffer_size);
+  if (!fderrstate.buffer)
+    return my_error_from_syserror ();
+
+  if (inextra)
+    {
+      err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
+      if (err)
+        {
+          log_error ("error running outbound pipe for extra fp: %s\n",
+                     gpg_strerror (err));
+          xfree (fderrstate.buffer);
+          return err;
+        }
+      exceptclose[0] = extrapipe[0]; /* Do not close in child. */
+      exceptclose[1] = -1;
+      /* Now find the argument marker and replace by the pipe's fd.
+         Yeah, that is an ugly non-thread safe hack but it safes us to
+         create a copy of the array.  */
+      snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
+      for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
+        if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
+          {
+            argsave = argv[argsaveidx];
+            argv[argsaveidx] = extrafdbuf;
+            break;
+          }
+    }
+  else
+    exceptclose[0] = -1;
 
-  err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT,
-                             NULL, GNUPG_SPAWN_NONBLOCK,
+  err = gnupg_spawn_process (pgmname, argv,
+                             exceptclose, NULL, GNUPG_SPAWN_NONBLOCK,
                              input? &infp : NULL,
                              &outfp, &errfp, &pid);
+  if (extrapipe[0] != -1)
+    close (extrapipe[0]);
+  if (argsave)
+    argv[argsaveidx] = argsave;
   if (err)
     {
       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
+      es_fclose (extrafp);
+      xfree (fderrstate.buffer);
       return err;
     }
 
-  fderrstate.pgmname = pgmname;
-
   fds[0].stream = infp;
   fds[0].want_write = 1;
   if (!input)
@@ -271,6 +382,11 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
   fds[1].want_read = 1;
   fds[2].stream = errfp;
   fds[2].want_read = 1;
+  fds[3].stream = extrafp;
+  fds[3].want_write = 1;
+  if (!inextra)
+    fds[3].ignore = 1;
+
   /* Now read as long as we have something to poll.  We continue
      reading even after EOF or error on stdout so that we get the
      other error messages or remaining outut.  */
@@ -291,7 +407,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
 
       if (fds[0].got_write)
         {
-          err = copy_buffer_do_copy (&cpbuf[0], input, fds[0].stream);
+          err = copy_buffer_do_copy (&cpbuf_in, input, fds[0].stream);
           if (err)
             {
               log_error ("error feeding data to '%s': %s\n",
@@ -301,7 +417,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
 
           if (es_feof (input))
             {
-              err = copy_buffer_flush (&cpbuf[0], fds[0].stream);
+              err = copy_buffer_flush (&cpbuf_in, fds[0].stream);
               if (err)
                 {
                   log_error ("error feeding data to '%s': %s\n",
@@ -314,9 +430,35 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
             }
         }
 
+      if (fds[3].got_write)
+        {
+          log_assert (inextra);
+          err = copy_buffer_do_copy (&cpbuf_extra, inextra, fds[3].stream);
+          if (err)
+            {
+              log_error ("error feeding data to '%s': %s\n",
+                         pgmname, gpg_strerror (err));
+              goto leave;
+            }
+
+          if (es_feof (inextra))
+            {
+              err = copy_buffer_flush (&cpbuf_extra, fds[3].stream);
+              if (err)
+                {
+                  log_error ("error feeding data to '%s': %s\n",
+                             pgmname, gpg_strerror (err));
+                  goto leave;
+                }
+
+              fds[3].ignore = 1; /* ready.  */
+              es_fclose (extrafp); extrafp = NULL;
+            }
+        }
+
       if (fds[1].got_read)
         {
-          err = copy_buffer_do_copy (&cpbuf[1], fds[1].stream, output);
+          err = copy_buffer_do_copy (&cpbuf_out, fds[1].stream, output);
           if (err)
             {
               log_error ("error reading data from '%s': %s\n",
@@ -329,7 +471,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
         read_and_log_stderr (&fderrstate, fds + 2);
     }
 
-  err = copy_buffer_flush (&cpbuf[1], output);
+  err = copy_buffer_flush (&cpbuf_out, output);
   if (err)
     {
       log_error ("error reading data from '%s': %s\n",
@@ -339,6 +481,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
 
   read_and_log_stderr (&fderrstate, NULL); /* Flush.  */
   es_fclose (infp); infp = NULL;
+  es_fclose (extrafp); extrafp = NULL;
   es_fclose (outfp); outfp = NULL;
   es_fclose (errfp); errfp = NULL;
 
@@ -350,14 +493,18 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
     gnupg_kill_process (pid);
 
   es_fclose (infp);
+  es_fclose (extrafp);
   es_fclose (outfp);
   es_fclose (errfp);
   if (pid != (pid_t)(-1))
     gnupg_wait_process (pgmname, pid, 1, NULL);
   gnupg_release_process (pid);
 
-  copy_buffer_shred (&cpbuf[0]);
-  copy_buffer_shred (&cpbuf[1]);
+  copy_buffer_shred (&cpbuf_in);
+  copy_buffer_shred (&cpbuf_out);
+  if (inextra)
+    copy_buffer_shred (&cpbuf_extra);
+  xfree (fderrstate.buffer);
   return err;
 }
 
@@ -408,7 +555,7 @@ gnupg_exec_tool (const char *pgmname, const char *argv[],
       goto leave;
     }
 
-  err = gnupg_exec_tool_stream (pgmname, argv, input, output);
+  err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output, NULL, NULL);
   if (err)
     goto leave;
 
index d9439aa..94091fd 100644 (file)
 
 #include <gpg-error.h>
 
+/* This callback can be used to process --status-fd outputs of GnuPG
+ * tools.  OPAQUE can be used to communicate between the caller of the
+ * function and the callback.  KEYWORD is the status keyword (see
+ * doc/DETAILS); it is never NULL.  ARGS are the arguments of the
+ * status line and will also never be NULL; the caller may modify this
+ * string.  */
+typedef void (*exec_tool_status_cb_t) (void *opaque,
+                                       const char *keyword,
+                                       char *args);
+
+
 /* Run the program PGMNAME with the command line arguments given in
    the NULL terminates array ARGV.  If INPUT_STRING is not NULL it
    will be fed to stdin of the process.  stderr is logged using
@@ -48,9 +59,11 @@ gpg_error_t gnupg_exec_tool (const char *pgmname, const char *argv[],
    the NULL terminates array ARGV.  If INPUT is not NULL it will be
    fed to stdin of the process.  stderr is logged using log_info and
    the process' stdout is written to OUTPUT.  On error a diagnostic is
-   printed, and an error code returned.  */
+   printed, and an error code returned.  INEXTRA is reserved. */
 gpg_error_t gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
-                                estream_t input,
-                                estream_t output);
+                                    estream_t input, estream_t inextra,
+                                    estream_t output,
+                                    exec_tool_status_cb_t status_cb,
+                                    void *status_cb_value);
 
 #endif /* GNUPG_COMMON_EXECTOOL_H */
index f1517fb..8f3137b 100644 (file)
@@ -47,7 +47,6 @@ static struct
 {
   gpg_err_source_t errsource;
   int verbosity;
-  const char *homedir;
   const char *agent_program;
   const char *lc_ctype;
   const char *lc_messages;
@@ -62,7 +61,6 @@ static struct
 void
 gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
                               int verbosity,
-                              const char *homedir,
                               const char *agent_program,
                               const char *opt_lc_ctype,
                               const char *opt_lc_messages,
@@ -70,7 +68,6 @@ gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
 {
   agentargs.errsource          = errsource;
   agentargs.verbosity          = verbosity;
-  agentargs.homedir            = homedir;
   agentargs.agent_program      = agent_program;
   agentargs.lc_ctype           = opt_lc_ctype;
   agentargs.lc_messages        = opt_lc_messages;
@@ -93,7 +90,6 @@ start_agent (void)
 
   err = start_new_gpg_agent (&agent_ctx,
                              agentargs.errsource,
-                             agentargs.homedir,
                              agentargs.agent_program,
                              agentargs.lc_ctype,
                              agentargs.lc_messages,
index a69262f..7e5cac0 100644 (file)
@@ -34,7 +34,6 @@
 
 void gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
                                    int verbosity,
-                                   const char *homedir,
                                    const char *agent_program,
                                    const char *opt_lc_ctype,
                                    const char *opt_lc_messages,
index 5bf5173..9a69022 100644 (file)
@@ -1,6 +1,6 @@
 /* homedir.c - Setup the home directory.
  * Copyright (C) 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
- * Copyright (C) 2013 Werner Koch
+ * Copyright (C) 2013, 2016 Werner Koch
  *
  * This file is part of GnuPG.
  *
 #endif
 #endif /*HAVE_W32_SYSTEM*/
 
+#ifdef HAVE_STAT
+#include <sys/stat.h> /* for stat() */
+#endif
+
 
 
 #include "util.h"
 #include "sysutils.h"
+#include "zb32.h"
+
+/* The GnuPG homedir.  This is only accessed by the functions
+ * gnupg_homedir and gnupg_set_homedir.  Malloced.  */
+static char *the_gnupg_homedir;
+
+/* Flag indicating that home directory is not the default one.  */
+static byte non_default_homedir;
+
 
 #ifdef HAVE_W32_SYSTEM
 /* A flag used to indicate that a control file for gpgconf has been
 
    This flag is not used on Unix systems.
  */
-static int w32_portable_app;
+static byte w32_portable_app;
 #endif /*HAVE_W32_SYSTEM*/
 
 #ifdef HAVE_W32_SYSTEM
 /* This flag is true if this process' binary has been installed under
    bin and not in the root directory as often used before GnuPG 2.1. */
-static int w32_bin_is_bin;
+static byte w32_bin_is_bin;
 #endif /*HAVE_W32_SYSTEM*/
 
 
@@ -144,6 +157,20 @@ w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
 #endif /*HAVE_W32_SYSTEM*/
 
 
+/* Check whether DIR is the default homedir.  */
+static int
+is_gnupg_default_homedir (const char *dir)
+{
+  int result;
+  char *a = make_absfilename (dir, NULL);
+  char *b = make_absfilename (GNUPG_DEFAULT_HOMEDIR, NULL);
+  result = !compare_filenames (a, b);
+  xfree (b);
+  xfree (a);
+  return result;
+}
+
+
 /* Get the standard home directory.  In general this function should
    not be used as it does not consider a registry value (under W32) or
    the GNUPGHOME environment variable.  It is better to use
@@ -242,6 +269,8 @@ default_homedir (void)
 #endif /*HAVE_W32_SYSTEM*/
   if (!dir || !*dir)
     dir = GNUPG_DEFAULT_HOMEDIR;
+  else if (!is_gnupg_default_homedir (dir))
+    non_default_homedir = 1;
 
   return dir;
 }
@@ -368,6 +397,241 @@ w32_commondir (void)
 #endif /*HAVE_W32_SYSTEM*/
 
 
+/* Change the homedir.  Some care must be taken to set this early
+ * enough because previous calls to gnupg_homedir may else return a
+ * different string.  */
+void
+gnupg_set_homedir (const char *newdir)
+{
+  if (!newdir || !*newdir)
+    newdir = default_homedir ();
+  else if (!is_gnupg_default_homedir (newdir))
+    non_default_homedir = 1;
+  xfree (the_gnupg_homedir);
+  the_gnupg_homedir = make_absfilename (newdir, NULL);;
+}
+
+
+/* Return the homedir.  The returned string is valid until another
+ * gnupg-set-homedir call.  This is always an absolute directory name.
+ * The function replaces the former global var opt.homedir.  */
+const char *
+gnupg_homedir (void)
+{
+  /* If a homedir has not been set, set it to the default.  */
+  if (!the_gnupg_homedir)
+    the_gnupg_homedir = make_absfilename (default_homedir (), NULL);
+  return the_gnupg_homedir;
+}
+
+
+/* Return whether the home dir is the default one.  */
+int
+gnupg_default_homedir_p (void)
+{
+  return !non_default_homedir;
+}
+
+
+/* Helper for gnupg-socketdir.  This is a global function, so that
+ * gpgconf can use it for its --create-socketdir command.  If
+ * SKIP_CHECKS is set permission checks etc. are not done.  The
+ * function always returns a malloced directory name and stores these
+ * bit flags at R_INFO:
+ *
+ *   1 := Internal error, stat failed, out of core, etc.
+ *   2 := No /run/user directory.
+ *   4 := Directory not owned by the user, not a directory
+ *        or wrong permissions.
+ *   8 := Same as 4 but for the subdir.
+ *  16 := mkdir failed
+ *  32 := Non default homedir; checking subdir.
+ *  64 := Subdir does not exist.
+ * 128 := Using homedir as fallback.
+ */
+char *
+_gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
+{
+#if defined(HAVE_W32_SYSTEM) || !defined(HAVE_STAT)
+
+  char *name;
+
+  (void)skip_checks;
+  *r_info = 0;
+  name = xstrdup (gnupg_homedir ());
+
+#else /* Unix and stat(2) available. */
+
+  static const char * const bases[] = { "/run", "/var/run", NULL};
+  int i;
+  struct stat sb;
+  char prefix[13 + 1 + 20 + 6 + 1];
+  const char *s;
+  char *name = NULL;
+
+  *r_info = 0;
+
+  /* First make sure that non_default_homedir can be set.  */
+  gnupg_homedir ();
+
+  /* It has been suggested to first check XDG_RUNTIME_DIR envvar.
+   * However, the specs state that the lifetime of the directory MUST
+   * be bound to the user being logged in.  Now GnuPG may also be run
+   * as a background process with no (desktop) user logged in.  Thus
+   * we better don't do that.  */
+
+  /* Check whether we have a /run/user dir.  */
+  for (i=0; bases[i]; i++)
+    {
+      snprintf (prefix, sizeof prefix, "%s/user/%u",
+                bases[i], (unsigned int)getuid ());
+      if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
+        break;
+    }
+  if (!bases[i])
+    {
+      *r_info |= 2; /* No /run/user directory.  */
+      goto leave;
+    }
+
+  if (sb.st_uid != getuid ())
+    {
+      *r_info |= 4; /* Not owned by the user.  */
+      if (!skip_checks)
+        goto leave;
+    }
+
+  if (strlen (prefix) + 7 >= sizeof prefix)
+    {
+      *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg".  */
+      goto leave;
+    }
+  strcat (prefix, "/gnupg");
+
+  /* Check whether the gnupg sub directory has proper permissions.  */
+  if (stat (prefix, &sb))
+    {
+      if (errno != ENOENT)
+        {
+          *r_info |= 1; /* stat failed.  */
+          goto leave;
+        }
+
+      /* Try to create the directory and check again.  */
+      if (gnupg_mkdir (prefix, "-rwx"))
+        {
+          *r_info |= 16; /* mkdir failed.  */
+          goto leave;
+        }
+      if (stat (prefix, &sb))
+        {
+          *r_info |= 1; /* stat failed.  */
+          goto leave;
+        }
+    }
+  /* Check that it is a directory, owned by the user, and only the
+   * user has permissions to use it.  */
+  if (!S_ISDIR(sb.st_mode)
+      || sb.st_uid != getuid ()
+      || (sb.st_mode & (S_IRWXG|S_IRWXO)))
+    {
+      *r_info |= 4; /* Bad permissions or not a directory. */
+      if (!skip_checks)
+        goto leave;
+    }
+
+  /* If a non default homedir is used, we check whether an
+   * corresponding sub directory below the socket dir is available
+   * and use that.  We has the non default homedir to keep the new
+   * subdir short enough.  */
+  if (non_default_homedir)
+    {
+      char sha1buf[20];
+      char *suffix;
+
+      *r_info |= 32; /* Testing subdir.  */
+      s = gnupg_homedir ();
+      gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, s, strlen (s));
+      suffix = zb32_encode (sha1buf, 8*15);
+      if (!suffix)
+        {
+          *r_info |= 1; /* Out of core etc. */
+          goto leave;
+        }
+      name = strconcat (prefix, "/d.", suffix, NULL);
+      xfree (suffix);
+      if (!name)
+        {
+          *r_info |= 1; /* Out of core etc. */
+          goto leave;
+        }
+
+      /* Stat that directory and check constraints.  Note that we
+       * do not auto create such a directory because we would not
+       * have a way to remove it.  Thus the directory needs to be
+       * pre-created.  The command
+       *    gpgconf --create-socketdir
+       * can be used tocreate that directory.  */
+      if (stat (name, &sb))
+        {
+          if (errno != ENOENT)
+            *r_info |= 1; /* stat failed. */
+          else
+            *r_info |= 64; /* Subdir does not exist.  */
+          if (!skip_checks)
+            {
+              xfree (name);
+              name = NULL;
+              goto leave;
+            }
+        }
+      else if (!S_ISDIR(sb.st_mode)
+               || sb.st_uid != getuid ()
+               || (sb.st_mode & (S_IRWXG|S_IRWXO)))
+        {
+          *r_info |= 8; /* Bad permissions or subdir is not a directory.  */
+          if (!skip_checks)
+            {
+              xfree (name);
+              name = NULL;
+              goto leave;
+            }
+        }
+    }
+  else
+    name = xstrdup (prefix);
+
+ leave:
+  /* If nothing works fall back to the homedir.  */
+  if (!name)
+    {
+      *r_info |= 128; /* Fallback.  */
+      name = xstrdup (gnupg_homedir ());
+    }
+
+#endif /* Unix */
+
+  return name;
+}
+
+
+/*
+ * Return the name of the socket dir.  That is the directory used for
+ * the IPC local sockets.  This is an absolute directory name.
+ */
+const char *
+gnupg_socketdir (void)
+{
+  static char *name;
+
+  if (!name)
+    {
+      unsigned int dummy;
+      name = _gnupg_socketdir_internal (0, &dummy);
+    }
+
+  return name;
+}
 
 
 /* Return the name of the sysconfdir.  This is a static string.  This
@@ -601,7 +865,7 @@ dirmngr_user_socket_name (void)
   static char *name;
 
   if (!name)
-    name = make_absfilename (default_homedir (), DIRMNGR_SOCK_NAME, NULL);
+    name = make_filename (gnupg_socketdir (), DIRMNGR_SOCK_NAME, NULL);
   return name;
 }
 
index 9175b4f..b6bafc7 100644 (file)
@@ -54,7 +54,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <assert.h>
-
+/* #include <execinfo.h> */
 
 #define GNUPG_COMMON_NEED_AFLOCAL 1
 #include "util.h"
@@ -748,6 +748,19 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
       if (missing_lf)
         es_putc_unlocked ('\n', logstream );
       es_funlockfile (logstream);
+      /* Using backtrace requires a configure test and to pass
+       * -rdynamic to gcc.  Thus we do not enable it now.  */
+      /* { */
+      /*   void *btbuf[20]; */
+      /*   int btidx, btlen; */
+      /*   char **btstr; */
+
+      /*   btlen = backtrace (btbuf, DIM (btbuf)); */
+      /*   btstr = backtrace_symbols (btbuf, btlen); */
+      /*   if (btstr) */
+      /*     for (btidx=0; btidx < btlen; btidx++) */
+      /*       log_debug ("[%d] %s\n", btidx, btstr[btidx]); */
+      /* } */
       abort ();
     }
   else
index 1b6d5f3..7c93547 100644 (file)
@@ -35,7 +35,7 @@
 #include <assert.h>
 
 #include "util.h"
-
+#include "openpgpdefs.h"
 
 /* A table with all our supported OpenPGP curves.  */
 static struct {
@@ -43,10 +43,11 @@ static struct {
   const char *oidstr; /* IETF formatted OID.  */
   unsigned int nbits; /* Nominal bit length of the curve.  */
   const char *alias;  /* NULL or alternative name of the curve.  */
+  int pubkey_algo;    /* Required OpenPGP algo or 0 for ECDSA/ECDH.  */
 } oidtable[] = {
 
-  { "Curve25519",      "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519" },
-  { "Ed25519",         "1.3.6.1.4.1.11591.15.1", 255, "ed25519" },
+  { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
+  { "Ed25519",    "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
 
   { "NIST P-256",      "1.2.840.10045.3.1.7",    256, "nistp256" },
   { "NIST P-384",      "1.3.132.0.34",           384, "nistp384" },
@@ -408,3 +409,29 @@ openpgp_enum_curves (int *iterp)
   *iterp = idx;
   return NULL;
 }
+
+
+/* Return the Libgcrypt name for for the gpg curve NAME if supported.
+ * If R_ALGO is not NULL the required OpenPGP public key algo or 0 is
+ * stored at that address.  NULL is returned if the curev is not
+ * supported. */
+const char *
+openpgp_is_curve_supported (const char *name, int *r_algo)
+{
+  int idx;
+
+  if (r_algo)
+    *r_algo = 0;
+  for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++)
+    {
+      if (!strcmp (name, (oidtable[idx].alias? oidtable[idx].alias
+                          /**/               : oidtable[idx].name))
+          && curve_supported_p (oidtable[idx].name))
+        {
+          if (r_algo)
+            *r_algo = oidtable[idx].pubkey_algo;
+          return oidtable[idx].name;
+        }
+    }
+  return NULL;
+}
index e200d6b..f8b86e1 100644 (file)
@@ -106,7 +106,7 @@ typedef enum
     SIGSUBPKT_PREF_HASH     = 21, /* Preferred hash algorithms. */
     SIGSUBPKT_PREF_COMPR    = 22, /* Preferred compression algorithms. */
     SIGSUBPKT_KS_FLAGS     = 23, /* Key server preferences. */
-    SIGSUBPKT_PREF_KS      = 24, /* Preferred key server. */
+    SIGSUBPKT_PREF_KS      = 24, /* Preferred keyserver. */
     SIGSUBPKT_PRIMARY_UID   = 25, /* Primary user id. */
     SIGSUBPKT_POLICY       = 26, /* Policy URL. */
     SIGSUBPKT_KEY_FLAGS     = 27, /* Key flags. */
index 730a75c..f9771c2 100644 (file)
@@ -96,6 +96,7 @@ enum
     STATUS_SIG_CREATED,
     STATUS_SESSION_KEY,
     STATUS_NOTATION_NAME,
+    STATUS_NOTATION_FLAGS,
     STATUS_NOTATION_DATA,
     STATUS_POLICY_URL,
     STATUS_KEY_CREATED,
@@ -105,6 +106,7 @@ enum
     STATUS_INV_SGNR,
     STATUS_NO_RECP,
     STATUS_NO_SGNR,
+    STATUS_KEY_CONSIDERED,
 
     STATUS_ALREADY_SIGNED,
     STATUS_KEYEXPIRED,
index 8b47a1c..0e96c9e 100644 (file)
@@ -1329,6 +1329,44 @@ strtokenize (const char *string, const char *delim)
 }
 
 
+/* Split a string into space delimited fields and remove leading and
+ * trailing spaces from each field.  A pointer to each field is stored
+ * in ARRAY.  Stop splitting at ARRAYSIZE fields.  The function
+ * modifies STRING.  The number of parsed fields is returned.
+ * Example:
+ *
+ *   char *fields[2];
+ *   if (split_fields (string, fields, DIM (fields)) < 2)
+ *     return  // Not enough args.
+ *   foo (fields[0]);
+ *   foo (fields[1]);
+ */
+int
+split_fields (char *string, char **array, int arraysize)
+{
+  int n = 0;
+  char *p, *pend;
+
+  for (p = string; *p == ' '; p++)
+    ;
+  do
+    {
+      if (n == arraysize)
+        break;
+      array[n++] = p;
+      pend = strchr (p, ' ');
+      if (!pend)
+        break;
+      *pend++ = 0;
+      for (p = pend; *p == ' '; p++)
+        ;
+    }
+  while (*p);
+
+  return n;
+}
+
+
 \f
 /* Version number parsing.  */
 
index d9225a3..b6f4167 100644 (file)
@@ -148,6 +148,10 @@ char **strsplit (char *string, char delim, char replacement, int *count);
 /* Tokenize STRING using the set of delimiters in DELIM.  */
 char **strtokenize (const char *string, const char *delim);
 
+/* Split STRING into space delimited fields and store them in the
+ * provided ARRAY.  */
+int split_fields (char *string, char **array, int arraysize);
+
 /* Return True if MYVERSION is greater or equal than REQ_VERSION.  */
 int compare_version_strings (const char *my_version, const char *req_version);
 
index 18625d0..0f7b7f5 100644 (file)
@@ -628,7 +628,7 @@ gnupg_mkdir (const char *name, const char *modestr)
 }
 
 
-/* A wrapper around mkdir which takes a string for the mode argument.
+/* A wrapper around chmod which takes a string for the mode argument.
    This makes it easier to handle the mode argument which is not
    defined on all systems.  The format of the modestring is the same
    as for gnupg_mkdir.  */
@@ -636,6 +636,8 @@ int
 gnupg_chmod (const char *name, const char *modestr)
 {
 #ifdef HAVE_W32_SYSTEM
+  (void)name;
+  (void)modestr;
   return 0;
 #else
   return chmod (name, modestr_to_mode (modestr));
diff --git a/common/t-ccparray.c b/common/t-ccparray.c
new file mode 100644 (file)
index 0000000..0512346
--- /dev/null
@@ -0,0 +1,93 @@
+/* t-ccparray.c - Module test for ccparray.c
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "ccparray.h"
+
+#define pass()  do { ; } while(0)
+#define fail(a)  do { fprintf (stderr, "%s:%d: test %d failed\n",\
+                               __FILE__,__LINE__, (a));          \
+                       exit (1);                                 \
+                    } while(0)
+
+
+static void
+run_test_1 (void)
+{
+  ccparray_t ccp;
+  const char **argv;
+  size_t nelem;
+
+  ccparray_init (&ccp, 0);
+  ccparray_put (&ccp, "First arg");
+  ccparray_put (&ccp, "Second arg");
+  ccparray_put (&ccp, NULL);
+  ccparray_put (&ccp, "Fourth arg");
+  argv = ccparray_get (&ccp, &nelem);
+  if (!argv)
+    {
+      fprintf (stderr, "error building array: %s\n", strerror (errno));
+      exit (1);
+    }
+
+  if (nelem != 4)
+    fail (1);
+
+  /* for (i=0; argv[i]; i++) */
+  /*   printf ("[%d] = '%s'\n", i, argv[i]); */
+  xfree (argv);
+}
+
+
+static void
+run_test_var (int count)
+{
+  ccparray_t ccp;
+  size_t nelem;
+  int i;
+
+  ccparray_init (&ccp, 0);
+  for (i=0; i < count; i++)
+    ccparray_put (&ccp, "An arg");
+  xfree (ccparray_get (&ccp, &nelem));
+  if (nelem != i)
+    fail (2);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  (void)argc;
+  (void)argv;
+
+  run_test_1 ();
+  run_test_var (0);
+  run_test_var (7);
+  run_test_var (8);
+  run_test_var (9);
+  run_test_var (4096);
+
+  return 0;
+}
index b4a41ac..4f4555e 100644 (file)
@@ -34,6 +34,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
 #ifdef HAVE_PWD_H
 # include <pwd.h>
 #endif
@@ -676,6 +677,82 @@ test_strtokenize (void)
     }
 }
 
+
+static void
+test_split_fields (void)
+{
+  struct {
+    const char *s;
+    int nfields;
+    const char *fields_expected[10];
+  } tv[] = {
+    {
+      "a bc cde fghi jklmn   foo ", 6,
+      { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL }
+    },
+    {
+      " a bc  def ", 2,
+      { "a", "bc", "def", NULL }
+    },
+    {
+      " a bc  def ", 3,
+      { "a", "bc", "def", NULL }
+    },
+    {
+      " a bc  def ", 4,
+      { "a", "bc", "def", NULL }
+    },
+    {
+      "", 0,
+      { NULL }
+    }
+  };
+
+  int tidx;
+  char *fields[10];
+  int field_count_expected, nfields, field_count, i;
+  char *s2;
+
+  for (tidx = 0; tidx < DIM(tv); tidx++)
+    {
+      nfields = tv[tidx].nfields;
+      assert (nfields <= DIM (fields));
+
+      /* Count the fields.  */
+      for (field_count_expected = 0;
+           tv[tidx].fields_expected[field_count_expected];
+           field_count_expected ++)
+        ;
+      if (field_count_expected > nfields)
+        field_count_expected = nfields;
+
+      /* We need to copy s since split_fields modifies in place.  */
+      s2 = xstrdup (tv[tidx].s);
+      field_count = split_fields (s2, fields, nfields);
+
+      if (field_count != field_count_expected)
+        {
+          printf ("%s: tidx %d: expected %d, got %d\n",
+                  __func__, tidx, field_count_expected, field_count);
+          fail (tidx * 1000);
+        }
+      else
+        {
+          for (i = 0; i < field_count_expected; i ++)
+            if (strcmp (tv[tidx].fields_expected[i], fields[i]))
+              {
+                printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n",
+                        __func__,
+                        tidx, i, tv[tidx].fields_expected[i], fields[i]);
+                fail (tidx * 1000 + i + 1);
+              }
+        }
+
+      xfree (s2);
+    }
+}
+
+
 static char *
 stresc (char *s)
 {
@@ -887,6 +964,7 @@ main (int argc, char **argv)
   test_make_absfilename_try ();
   test_strsplit ();
   test_strtokenize ();
+  test_split_fields ();
   test_compare_version_strings ();
   test_format_text ();
 
index 84a15ab..c84847a 100644 (file)
@@ -214,12 +214,16 @@ int openpgp_oid_is_crv25519 (gcry_mpi_t a);
 const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits);
 const char *openpgp_oid_to_curve (const char *oid, int canon);
 const char *openpgp_enum_curves (int *idxp);
-
+const char *openpgp_is_curve_supported (const char *name, int *r_algo);
 
 
 /*-- homedir.c --*/
 const char *standard_homedir (void);
 const char *default_homedir (void);
+void gnupg_set_homedir (const char *newdir);
+const char *gnupg_homedir (void);
+int gnupg_default_homedir_p (void);
+const char *gnupg_socketdir (void);
 const char *gnupg_sysconfdir (void);
 const char *gnupg_bindir (void);
 const char *gnupg_libexecdir (void);
@@ -230,6 +234,8 @@ const char *gnupg_cachedir (void);
 const char *dirmngr_sys_socket_name (void);
 const char *dirmngr_user_socket_name (void);
 
+char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
+
 /* All module names.  We also include gpg and gpgsm for the sake for
    gpgconf. */
 #define GNUPG_MODULE_NAME_AGENT        1
index 6aeca17..1b8a6fc 100644 (file)
@@ -28,7 +28,7 @@ min_automake_version="1.14"
 m4_define([mym4_package],[gnupg])
 m4_define([mym4_major], [2])
 m4_define([mym4_minor], [1])
-m4_define([mym4_micro], [12])
+m4_define([mym4_micro], [13])
 
 # To start a new development series, i.e a new major or minor number
 # you need to mark an arbitrary commit before the first beta release
@@ -787,24 +787,28 @@ AM_PATH_KSBA("$NEED_KSBA_API:$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no)
 if test "$use_ccid_driver" = auto || test "$use_ccid_driver" = yes; then
    case "${host}" in
      *-mingw32*)
+       LIBUSB_NAME=
        LIBUSB_LIBS=
        LIBUSB_CPPFLAGS=
        ;;
      *-*-darwin*)
-       LIBUSB_LIBS="-lusb-1.0 -Wl,-framework,CoreFoundation -Wl,-framework,IOKit"
+       LIBUSB_NAME=usb-1.0
+       LIBUSB_LIBS="-Wl,-framework,CoreFoundation -Wl,-framework,IOKit"
        ;;
      *-*-freebsd*)
        # FreeBSD has a native 1.0 compatible library by -lusb.
-       LIBUSB_LIBS="-lusb"
+       LIBUSB_NAME=usb
+       LIBUSB_LIBS=
        ;;
      *)
-       LIBUSB_LIBS="-lusb-1.0"
+       LIBUSB_NAME=usb-1.0
+       LIBUSB_LIBS=
        ;;
    esac
 fi
-if test x"$LIBUSB_LIBS" != x ; then
-   AC_CHECK_LIB(usb-1.0, libusb_init,
-                [ LIBUSB_LIBS="$LIBUSB_LIBS"
+if test x"$LIBUSB_NAME" != x ; then
+   AC_CHECK_LIB($LIBUSB_NAME, libusb_init,
+                [ LIBUSB_LIBS="-l$LIBUSB_NAME $LIBUSB_LIBS"
                   have_libusb=yes ])
    AC_MSG_CHECKING([libusb include dir])
    usb_incdir_found="no"
@@ -1379,7 +1383,7 @@ AC_CHECK_FUNCS([waitpid wait4 sigaction sigprocmask pipe getaddrinfo])
 AC_CHECK_FUNCS([ttyname rand ftello fsync stat lstat])
 AC_CHECK_FUNCS([memicmp stpcpy strsep strlwr strtoul memmove stricmp strtol \
                 memrchr isascii timegm getrusage setrlimit stat setlocale   \
-                flockfile funlockfile fopencookie funopen getpwnam getpwuid \
+                flockfile funlockfile getpwnam getpwuid \
                 getenv inet_pton strpbrk])
 
 if test "$have_android_system" = yes; then
@@ -1772,12 +1776,13 @@ AC_ARG_ENABLE([build-timestamp],
         BUILD_TIMESTAMP=`date -u +%Y-%m-%dT%H:%M+0000 2>/dev/null || date`
       else
         BUILD_TIMESTAMP="$enableval"
-      fi],
-     [BUILD_TIMESTAMP="<none>"])
+      fi
+      BUILD_HOSTNAME="$ac_hostname"],
+     [BUILD_TIMESTAMP="<none>"
+      BUILD_HOSTNAME="<anon>"])
 AC_SUBST(BUILD_TIMESTAMP)
 AC_DEFINE_UNQUOTED(BUILD_TIMESTAMP, "$BUILD_TIMESTAMP",
                    [The time this package was configured for a build])
-BUILD_HOSTNAME="$ac_hostname"
 AC_SUBST(BUILD_HOSTNAME)
 
 
index cbc0090..aaa9050 100644 (file)
@@ -99,18 +99,17 @@ dirmngr_ldap_LDADD = $(libcommon) no-libgcrypt.o \
 endif
 
 dirmngr_client_SOURCES = dirmngr-client.c
-dirmngr_client_LDADD = $(libcommon) no-libgcrypt.o \
-                       $(LIBASSUAN_LIBS) \
-                      $(GPG_ERROR_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV)
+dirmngr_client_LDADD = $(libcommon) \
+                       $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
+                       $(LIBGCRYPT_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV)
 dirmngr_client_LDFLAGS = $(extra_bin_ldflags)
 
-
 no-libgcrypt.c : $(top_srcdir)/tools/no-libgcrypt.c
        cat $(top_srcdir)/tools/no-libgcrypt.c > no-libgcrypt.c
 
 
 t_common_src = t-support.h
-t_common_ldadd = $(libcommon) no-libgcrypt.o $(LIBASSUAN_LIBS) \
+t_common_ldadd = $(libcommon) $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
                  $(GPG_ERROR_LIBS) $(NETLIBS) \
                  $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
                  $(DNSLIBS) $(LIBINTL) $(LIBICONV)
index c6a33d7..9b004cc 100644 (file)
@@ -298,7 +298,6 @@ main (int argc, char **argv )
 
   err = start_new_dirmngr (&ctx,
                            GPG_ERR_SOURCE_DEFAULT,
-                           default_homedir (),
                            opt.dirmngr_program
                              ? opt.dirmngr_program
                              : gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR),
index f249d68..7e629db 100644 (file)
@@ -795,9 +795,7 @@ main (int argc, char **argv)
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
 
-  opt.homedir = default_homedir ();
-
-  /* Now with NPth running we can set the logging callback.  Our
+    /* Now with NPth running we can set the logging callback.  Our
      windows implementation does not yet feature the NPth TLS
      functions.  */
 #ifndef HAVE_W32_SYSTEM
@@ -835,7 +833,7 @@ main (int argc, char **argv)
         default_config = 0; /* --no-options */
       else if (pargs.r_opt == oHomedir)
         {
-          opt.homedir = pargs.r.ret_str;
+          gnupg_set_homedir (pargs.r.ret_str);
           homedir_seen = 1;
         }
       else if (pargs.r_opt == aDaemon)
@@ -862,9 +860,9 @@ main (int argc, char **argv)
   if (opt.system_daemon && !homedir_seen)
     {
 #ifdef HAVE_W32CE_SYSTEM
-      opt.homedir = DIRSEP_S "gnupg";
+      gnupg_set_homedir (DIRSEP_S "gnupg");
 #else
-      opt.homedir = gnupg_sysconfdir ();
+      gnupg_set_homedir (gnupg_sysconfdir ());
 #endif
       opt.homedir_cache = gnupg_cachedir ();
       socket_name = dirmngr_sys_socket_name ();
@@ -875,7 +873,7 @@ main (int argc, char **argv)
     socket_name = dirmngr_sys_socket_name ();
 
   if (default_config)
-    configname = make_filename (opt.homedir, DIRMNGR_NAME".conf", NULL );
+    configname = make_filename (gnupg_homedir (), DIRMNGR_NAME".conf", NULL );
 
   argc = orig_argc;
   argv = orig_argv;
@@ -989,7 +987,7 @@ main (int argc, char **argv)
     greeting = 0;
 
   if (!opt.homedir_cache)
-    opt.homedir_cache = opt.homedir;
+    opt.homedir_cache = xstrdup (gnupg_homedir ());
 
   if (greeting)
     {
@@ -1019,7 +1017,8 @@ main (int argc, char **argv)
           log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
     }
 
-  if (!access ("/etc/"DIRMNGR_NAME, F_OK) && !strncmp (opt.homedir, "/etc/", 5))
+  if (!access ("/etc/"DIRMNGR_NAME, F_OK)
+      && !strncmp (gnupg_homedir (), "/etc/", 5))
     log_info
       ("NOTE: DirMngr is now a proper part of %s.  The configuration and"
        " other directory names changed.  Please check that no other version"
@@ -1043,7 +1042,7 @@ main (int argc, char **argv)
 #if USE_LDAP
   if (!ldapfile)
     {
-      ldapfile = make_filename (opt.homedir,
+      ldapfile = make_filename (gnupg_homedir (),
                                 opt.system_daemon?
                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
                                 NULL);
@@ -1184,6 +1183,10 @@ main (int argc, char **argv)
         }
       cleanup_socket = 1;
 
+      if (gnupg_chmod (serv_addr.sun_path, "-rwx"))
+        log_error (_("can't set permissions of '%s': %s\n"),
+                   serv_addr.sun_path, strerror (errno));
+
       if (listen (FD2INT (fd), 5) == -1)
         {
           log_error (_("listen() failed: %s\n"), strerror (errno));
@@ -1396,7 +1399,7 @@ main (int argc, char **argv)
       /* First the configuration file.  This is not an option, but it
         is vital information for GPG Conf.  */
       if (!opt.config_filename)
-        opt.config_filename = make_filename (opt.homedir,
+        opt.config_filename = make_filename (gnupg_homedir (),
                                              "dirmngr.conf", NULL );
 
       filename = percent_escape (opt.config_filename, NULL);
@@ -1416,7 +1419,7 @@ main (int argc, char **argv)
          and having both of them is thus problematic.  --no-detach is
          also only usable on the command line.  --batch is unused.  */
 
-      filename = make_filename (opt.homedir,
+      filename = make_filename (gnupg_homedir (),
                                 opt.system_daemon?
                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
                                 NULL);
@@ -1658,7 +1661,7 @@ parse_ocsp_signer (const char *string)
     {
       if (string[0] == '.' && string[1] == '/' )
         string += 2;
-      fname = make_filename (opt.homedir, string, NULL);
+      fname = make_filename (gnupg_homedir (), string, NULL);
     }
 
   fp = es_fopen (fname, "r");
index 6078884..8d90ae4 100644 (file)
@@ -79,8 +79,7 @@ struct
   int quiet;          /* be as quiet as possible */
   int dry_run;        /* don't change any persistent data */
   int batch;          /* batch mode */
-  const char *homedir;      /* Configuration directory name */
-  const char *homedir_cache; /* Ditto for cache files (/var/cache/dirmngr).  */
+  const char *homedir_cache; /* Dir for cache files (/var/cache/dirmngr).  */
 
   char *config_filename;     /* Name of a config file, which will be
                                 reread on a HUP if it is not NULL. */
index 6309413..c5702b1 100644 (file)
@@ -641,10 +641,23 @@ fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp)
   /* Fixme:  Can we use MYOPT->user or is it shared with other theeads?.  */
   ret = my_ldap_simple_bind_s (ld, myopt->user, myopt->pass);
   npth_protect ();
+#ifdef LDAP_VERSION3
+  if (ret == LDAP_PROTOCOL_ERROR)
+    {
+      /* Protocol error could mean that the server only supports v3. */
+      int version = LDAP_VERSION3;
+      if (myopt->verbose)
+        log_info ("protocol error; retrying bind with v3 protocol\n");
+      npth_unprotect ();
+      ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+      ret = my_ldap_simple_bind_s (ld, myopt->user, myopt->pass);
+      npth_protect ();
+    }
+#endif
   if (ret)
     {
       log_error (_("binding to '%s:%d' failed: %s\n"),
-                 host, port, strerror (errno));
+                 host, port, ldap_err2string (ret));
       ldap_unbind (ld);
       return -1;
     }
index f0fcd0d..941ad4f 100644 (file)
@@ -937,7 +937,7 @@ http_wait_response (http_t hd)
 
   /* Shutdown one end of the socket is desired.  As per HTTP/1.0 this
      is not required but some very old servers (e.g. the original pksd
-     key server didn't worked without it.  */
+     keyserver didn't worked without it.  */
   if ((hd->flags & HTTP_FLAG_SHUTDOWN))
     shutdown (hd->sock->fd, 1);
   hd->in_data = 0;
index c073f17..55fcd8b 100644 (file)
@@ -695,10 +695,10 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
       return err;
     }
 
-  err = gnupg_create_inbound_pipe (outpipe);
+  err = gnupg_create_inbound_pipe (outpipe, NULL, 0);
   if (!err)
     {
-      err = gnupg_create_inbound_pipe (errpipe);
+      err = gnupg_create_inbound_pipe (errpipe, NULL, 0);
       if (err)
         {
           close (outpipe[0]);
index 80ce5b5..6eb6f1b 100644 (file)
@@ -834,8 +834,6 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
   uri = strconcat ("https://",
                    domain,
                    "/.well-known/openpgpkey/hu/",
-                   domain,
-                   "/",
                    encodedhash,
                    NULL);
   if (!uri)
@@ -2442,22 +2440,13 @@ start_command_handler (assuan_fd_t fd)
 
   if (!hello_line)
     {
-      size_t n;
-      const char *cfgname;
-
-      cfgname = opt.config_filename? opt.config_filename : "[none]";
-
-      n = (30 + strlen (opt.homedir) + strlen (cfgname)
-           + strlen (hello) + 1);
-      hello_line = xmalloc (n+1);
-      snprintf (hello_line, n,
-                "Home: %s\n"
-                "Config: %s\n"
-                "%s",
-                opt.homedir,
-                cfgname,
-                hello);
-      hello_line[n] = 0;
+      hello_line = xtryasprintf
+        ("Home: %s\n"
+         "Config: %s\n"
+         "%s",
+         gnupg_homedir (),
+         opt.config_filename? opt.config_filename : "[none]",
+         hello);
     }
 
   ctrl->server_local->assuan_ctx = ctx;
index 5ceab68..4b3f0af 100644 (file)
@@ -341,10 +341,12 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
   arguments in future versions.
 
 ** General status codes
-*** NEWSIG
+*** NEWSIG [<signers_uid>]
     Is issued right before a signature verification starts.  This is
-    useful to define a context for parsing ERROR status messages.  No
-    arguments are currently defined.
+    useful to define a context for parsing ERROR status messages.
+    arguments are currently defined.  If SIGNERS_UID is given and is
+    not "-" this is the percent escape value of the OpenPGP Signer's
+    User ID signature sub-packet.
 
 *** GOODSIG  <long_keyid_or_fpr>  <username>
     The signature with the keyid is good.  For each signature only one
@@ -520,14 +522,17 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     letter 'T'.
 
 *** NOTATION_
-    There are actually two related status codes to convey notation
+    There are actually three related status codes to convey notation
     data:
 
     - NOTATION_NAME <name>
+    - NOTATION_FLAGS <critical> <human_readable>
     - NOTATION_DATA <string>
 
-    <name> and <string> are %XX escaped; the data may be split among
-    several NOTATION_DATA lines.
+    <name> and <string> are %XX escaped.  The data may be split among
+    several NOTATION_DATA lines.  NOTATION_FLAGS is emitted after
+    NOTATION_NAME and gives the critical and human readable flags;
+    the flag values are either 0 or 1.
 
 *** POLICY_URL <string>
     Note that URL in <string> is %XX escaped.
@@ -548,7 +553,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     that case, this status tag does not appear.
 
 *** ATTRIBUTE <arguments>
-    The list or argemnts are:
+    The list or arguments are:
     - <fpr>
     - <octets>
     - <type>
@@ -602,18 +607,29 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
        - 13 :: Key disabled
        - 14 :: Syntax error in specification
 
+    If no specific reason was given a previously emitted status code
+    KEY_CONSIDERED may be used to analyzed the problem.
+
     Note that for historical reasons the INV_RECP status is also used
     for gpgsm's SIGNER command where it relates to signer's of course.
     Newer GnuPG versions are using INV_SGNR; applications should
     ignore the INV_RECP during the sender's command processing once
     they have seen an INV_SGNR.  Different codes are used so that they
     can be distinguish while doing an encrypt+sign operation.
+
 *** NO_RECP <reserved>
     Issued if no recipients are usable.
 
 *** NO_SGNR <reserved>
     Issued if no senders are usable.
 
+*** KEY_CONSIDERED <fpr> <flags>
+    Issued to explian the lookup of a key.  FPR is the hexified
+    fingerprint of the primary key.  The bit values for FLAGS are:
+
+    - 1 :: The key has not been selected.
+    - 2 :: All subkeys of the key are expired or have been revoked.
+
 *** KEYEXPIRED <expire-timestamp>
     The key has expired.  expire-timestamp is the expiration time in
     seconds since Epoch.  This status line is not very useful because
@@ -677,7 +693,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
 
     This status identifies the key and the userid for all following
     Tofu information.  The fingerprint is the fingerprint of the
-    primary key and the mbox is in general the mailbox part of the
+    primary key and the mbox is in general the addr-spec part of the
     userid encoded in UTF-8 and percent escaped.
 
 *** TOFU_STATS <validity> <sign-count> 0 [<policy> [<tm1> <tm2>]]
@@ -719,8 +735,8 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
 *** PKA_TRUST_
     This is is one:
 
-    - PKA_TRUST_GOOD <mailbox>
-    - PKA_TRUST_BAD  <mailbox>
+    - PKA_TRUST_GOOD <addr-spec>
+    - PKA_TRUST_BAD  <addr-spec>
 
     Depending on the outcome of the PKA check one of the above status
     codes is emitted in addition to a =TRUST_*= status.
@@ -1250,7 +1266,7 @@ Status codes are:
       /pks/lookup/<gnupg_formatierte_user_id>?op=<operation>
 
    This can be implemented using Hurd's translator mechanism.
-   However, I think the whole key server stuff has to be re-thought;
+   However, I think the whole keyserver stuff has to be re-thought;
    I have some ideas and probably create a white paper.
 ** Algorithm names for the "keygen.algo" prompt
 
index 5b73d7b..e87442f 100644 (file)
@@ -312,6 +312,7 @@ value to access HTTP servers.
 
 @item --http-proxy @var{host}[:@var{port}]
 @opindex http-proxy
+@efindex http_proxy
 Use @var{host} and @var{port} to access HTTP servers.  The use of this
 option overrides the environment variable @env{http_proxy} regardless
 whether @option{--honor-http-proxy} has been set.
index d0e5199..c99c129 100644 (file)
 @macro mancont
 @end macro
 
+
+
 @c Create a separate index for command line options.
 @defcodeindex op
-@c Merge the standard indexes into a single one.
+@c Create an index vor environment variables and files.
+@defcodeindex ef
+
+@c Merge the function index into the concept index.
 @syncodeindex fn cp
+@c Merge the variable index into the concept index.
 @syncodeindex vr cp
+@c Merge the keystroke index into the concept index.
 @syncodeindex ky cp
+@c Merge the program index into the concept index.
 @syncodeindex pg cp
+@c Merge the data type index into the concept index.
 @syncodeindex tp cp
 @c %**end of header
 @copying
@@ -144,6 +153,7 @@ the administration and the architecture.
 
 * Glossary::            Short description of terms used.
 * Option Index::        Index to command line options.
+* Environment Index::   Index to environment variables and files.
 * Index::              Index of concepts and symbol names.
 @end menu
 
@@ -192,6 +202,11 @@ the administration and the architecture.
 
 @printindex op
 
+@node Environment Index
+@unnumbered Environment Variable and File Index
+
+@printindex ef
+
 @node Index
 @unnumbered Index
 
index 2989d3b..37774dd 100644 (file)
@@ -85,6 +85,7 @@ gpg-connect-agent /bye
 @end example
 
 @noindent
+@efindex GPG_TTY
 You should always add the following lines to your @code{.bashrc} or
 whatever initialization file is used for all shell invocations:
 
@@ -295,6 +296,7 @@ debugging.
 @itemx --csh
 @opindex sh
 @opindex csh
+@efindex SHELL
 Format the info output in daemon mode for use with the standard Bourne
 shell or the C-shell respectively.  The default is to guess it based on
 the environment variable @code{SHELL} which is correct in almost all
@@ -309,6 +311,7 @@ should in general not be used to avoid X-sniffing attacks.
 @anchor{option --log-file}
 @item --log-file @var{file}
 @opindex log-file
+@efindex HKCU\Software\GNU\GnuPG:DefaultLogFile
 Append all logging output to @var{file}.  This is very helpful in seeing
 what the agent actually does.  If neither a log file nor a log file
 descriptor has been set on a Windows platform, the Registry entry
@@ -337,6 +340,10 @@ internal cache of @command{gpg-agent} with passphrases.
 Disallow or allow clients to use the loopback pinentry features; see
 the option @option{pinentry-mode} for details.  Allow is the default.
 
+The @option{--force} option of the Assuan command @command{DELETE_KEY}
+is also controlled by this option: The option is ignored if a loopback
+pinentry is disallowed.
+
 @item --no-allow-external-cache
 @opindex no-allow-external-cache
 Tell Pinentry not to enable features which use an external cache for
@@ -609,7 +616,7 @@ agent. By default they may all be found in the current home directory
 @table @file
 
 @item gpg-agent.conf
-@cindex gpg-agent.conf
+@efindex gpg-agent.conf
   This is the standard configuration file read by @command{gpg-agent} on
   startup.  It may contain any valid long option; the leading
   two dashes may not be entered and the option may not be abbreviated.
@@ -619,6 +626,7 @@ agent. By default they may all be found in the current home directory
   You should backup this file.
 
 @item trustlist.txt
+@efindex trustlist.txt
   This is the list of trusted keys.  You should backup this file.
 
   Comment lines, indicated by a leading hash mark, as well as empty
@@ -680,7 +688,7 @@ fails, try again using the chain validation model.
 
 
 @item sshcontrol
-@cindex sshcontrol
+@efindex sshcontrol
 This file is used when support for the secure shell agent protocol has
 been enabled (@pxref{option --enable-ssh-support}). Only keys present in
 this file are used in the SSH protocol.  You should backup this file.
@@ -714,6 +722,7 @@ implicitly added to this list; i.e. there is no need to list them.
 @end cartouche
 
 @item private-keys-v1.d/
+@efindex private-keys-v1.d
 
   This is the directory where gpg-agent stores the private keys.  Each
   key is stored in a file with the name made up of the keygrip and the
@@ -790,7 +799,7 @@ This signal is used for internal purposes.
 @node Agent Examples
 @section Examples
 
-It is important to set the GPG_TTY environment variable in
+It is important to set the environment variable @code{GPG_TTY} in
 your login shell, for example in the @file{~/.bashrc} init script:
 
 @cartouche
@@ -820,8 +829,17 @@ fi
 @section Agent's Assuan Protocol
 
 Note: this section does only document the protocol, which is used by
-GnuPG components; it does not deal with the ssh-agent protocol.
+GnuPG components; it does not deal with the ssh-agent protocol.  To
+see the full specification of each command, use
+
+@example
+  gpg-connect-agent 'help COMMAND' /bye
+@end example
 
+@noindent
+or just 'help' to list all available commands.
+
+@noindent
 The @command{gpg-agent} daemon is started on demand by the GnuPG
 components.
 
index 3cad361..be80450 100644 (file)
@@ -342,7 +342,8 @@ fingerprints. This is the same output as @option{--list-keys} but with
 the additional output of a line with the fingerprint. May also be
 combined with @option{--list-sigs} or @option{--check-sigs}.  If this
 command is given twice, the fingerprints of all secondary keys are
-listed too.
+listed too.  This command also forces pretty printing of fingerprints
+if the keyid format has been set to "none".
 
 @item --list-packets
 @opindex list-packets
@@ -376,13 +377,20 @@ safeguard against accidental deletion of multiple keys.
 
 @item --delete-secret-keys @code{name}
 @opindex delete-secret-keys
-Remove key from the secret keyring. In batch mode the key
-must be specified by fingerprint.
+gRemove key from the secret keyring. In batch mode the key must be
+specified by fingerprint.  The option @option{--yes} can be used to
+advice gpg-agent not to request a confirmation.  This extra
+pre-caution is done because @command{gpg} can't be sure that the
+secret key (as controlled by gpg-agent) is only used for the given
+OpenPGP public key.
+
 
 @item --delete-secret-and-public-key @code{name}
 @opindex delete-secret-and-public-key
 Same as @option{--delete-key}, but if a secret key exists, it will be
 removed first. In batch mode the key must be specified by fingerprint.
+The option @option{--yes} can be used to advice gpg-agent not to
+request a confirmation.
 
 @item --export
 @opindex export
@@ -592,7 +600,7 @@ This section explains the main commands for key management
 
 @table @gnupgtabopt
 
-@item --quick-gen-key @code{user-id}
+@item --quick-gen-key @code{user-id} [@code{algo} [@code{usage} [@code{expire}]]]
 @opindex quick-gen-key
 This is a simple command to generate a standard key with one user id.
 In contrast to @option{--gen-key} the key is generated directly
@@ -605,6 +613,13 @@ answer to a ``Continue?'' style confirmation prompt is required.  In
 case the user id already exists in the key ring a second prompt to
 force the creation of the key will show up.
 
+If any of the optional arguments are given, only the primary key is
+created and no prompts are shown.  For a description of these optional
+arguments see the command @code{--quick-addkey}.  The @code{usage}
+accepts also the value ``cert'' which can be used to create a
+certification only primary key; the default is to a create
+certification and signing key.
+
 If this command is used with @option{--batch},
 @option{--pinentry-mode} has been set to @code{loopback}, and one of
 the passphrase options (@option{--passphrase},
@@ -613,6 +628,35 @@ supplied passphrase is used for the new key and the agent does not ask
 for it.  To create a key without any protection @code{--passphrase ''}
 may be used.
 
+@item --quick-addkey @code{fpr} [@code{algo} [@code{usage} [@code{expire}]]]
+@opindex quick-addkey
+Directly add a subkey to the key identified by the fingerprint
+@code{fpr}.  Without the optional arguments an encryption subkey is
+added.  If any of the arguments are given a more specific subkey is
+added.
+
+@code{algo} may be any of the supported algorithms or curve names given
+in the format as used by key listings.  To use the default algorithm
+the string ``default'' or ``-'' can be used. Supported algorithms are
+``rsa'', ``dsa'', ``elg'', ``ed25519'', ``cv25519'', and other ECC
+curves.  For example the string ``rsa'' adds an RSA key with the
+default key length; a string ``rsa4096'' requests that the key length
+is 4096 bits.
+
+Depending on the given @code{algo} the subkey may either be an
+encryption subkey or a signing subkey.  If an algorithm is capable of
+signing and encryption and such a subkey is desired, a @code{usage}
+string must be given.  This string is either ``default'' or ``-'' to
+keep the default or a comma delimited list of keywords: ``sign'' for a
+signing subkey, ``auth'' for an authentication subkey, and ``encr''
+for an encryption subkey (``encrypt'' can be used as alias for
+``encr'').  The valid combinations depend on the algorithm.
+
+The @code{expire} argument can be used to specify an expiration date
+for the subkey.  Several formats are supported; commonly the ISO
+YYYY-MM-DD format is used.  The values ``never'', ``none'', or ``-''
+can be used for no expiration date.
+
 @item --gen-key
 @opindex gen-key
 Generate a new key pair using the current default parameters.  This is
@@ -629,6 +673,7 @@ There is also a feature which allows you to create keys in batch
 mode. See the manual section ``Unattended key generation'' on how
 to use this.
 
+
 @item --gen-revoke @code{name}
 @opindex gen-revoke
 Generate a revocation certificate for the complete key.  To only revoke
@@ -1247,8 +1292,8 @@ the opposite meaning. The options are:
   Enable PKA lookups to verify sender addresses. Note that PKA is based
   on DNS, and so enabling this option may disclose information on when
   and what signatures are verified or to whom data is encrypted. This
-  is similar to the "web bug" described for the auto-key-retrieve
-  feature.
+  is similar to the "web bug" described for the @option{--auto-key-retrieve}
+  option.
 
   @item pka-trust-increase
   @opindex verify-options:pka-trust-increase
@@ -1296,9 +1341,10 @@ executing it from GnuPG does not make it secure.
 
 @item --exec-path @code{string}
 @opindex exec-path
+@efindex PATH
 Sets a list of directories to search for photo viewers and keyserver
 helpers. If not provided, keyserver helpers use the compiled-in
-default directory, and photo viewers use the $PATH environment
+default directory, and photo viewers use the @code{PATH} environment
 variable.
 Note, that on W32 system this value is ignored when searching for
 keyserver helpers.
@@ -1635,13 +1681,34 @@ mechanisms, in the order they are to be tried:
 
 @end table
 
-@item --keyid-format @code{short|0xshort|long|0xlong}
+@item --auto-key-retrieve
+@itemx --no-auto-key-retrieve
+@opindex auto-key-retrieve
+@opindex no-auto-key-retrieve
+This option enables the automatic retrieving of keys from a keyserver
+when verifying signatures made by keys that are not on the local
+keyring.
+
+If the method "wkd" is included in the list of methods given to
+@option{auto-key-locate}, the Signer's User ID is part of the
+signature, and the option @option{--disable-signer-uid} is not used,
+the "wkd" method may also be used to retrieve a key.
+
+Note that this option makes a "web bug" like behavior possible.
+Keyserver or Web Key Directory operators can see which keys you
+request, so by sending you a message signed by a brand new key (which
+you naturally will not have on your local keyring), the operator can
+tell both your IP address and the time when you verified the
+signature.
+
+@item --keyid-format @code{none|short|0xshort|long|0xlong}
 @opindex keyid-format
-Select how to display key IDs. "short" is the traditional 8-character
-key ID. "long" is the more accurate (but less convenient)
-16-character key ID. Add an "0x" to either to include an "0x" at the
-beginning of the key ID, as in 0x99242560.  Note that this option is
-ignored if the option --with-colons is used.
+Select how to display key IDs.  "none" does not show the key ID at all
+but shows the fingerprint in a separate line.  "short" is the
+traditional 8-character key ID.  "long" is the more accurate (but less
+convenient) 16-character key ID.  Add an "0x" to either to include an
+"0x" at the beginning of the key ID, as in 0x99242560.  Note that this
+option is ignored if the option @option{--with-colons} is used.
 
 @item --keyserver @code{name}
 @opindex keyserver
@@ -1692,15 +1759,7 @@ are available for all keyserver types, some common options are:
   used with HKP keyservers.
 
   @item auto-key-retrieve
-  This option enables the automatic retrieving of keys from a keyserver
-  when verifying signatures made by keys that are not on the local
-  keyring.
-
-  Note that this option makes a "web bug" like behavior possible.
-  Keyserver operators can see which keys you request, so by sending you
-  a message signed by a brand new key (which you naturally will not have
-  on your local keyring), the operator can tell both your IP address and
-  the time when you verified the signature.
+  This is the same as the option @option{auto-key-retrieve}.
 
   @item honor-keyserver-url
   When using @option{--refresh-keys}, if the key in question has a preferred
@@ -1712,9 +1771,9 @@ are available for all keyserver types, some common options are:
   refreshed.  Thus this option is not enabled by default.
 
   @item honor-pka-record
-  If auto-key-retrieve is set, and the signature being verified has a
-  PKA record, then use the PKA information to fetch the key. Defaults
-  to "yes".
+  If @option{--auto-key-retrieve} is used, and the signature being
+  verified has a PKA record, then use the PKA information to fetch
+  the key. Defaults to "yes".
 
   @item include-subkeys
   When receiving a key, include subkeys as potential targets. Note that
@@ -1828,9 +1887,7 @@ file name.
 @item --dirmngr-program @var{file}
 @opindex dirmngr-program
 Specify a dirmngr program to be used for keyserver access.  The
-default value is @file{@value{BINDIR}/dirmngr}.  This is only used as a
-fallback when the environment variable @code{DIRMNGR_INFO} is not set or
-a running dirmngr cannot be connected.
+default value is @file{@value{BINDIR}/dirmngr}.
 
 @item --no-autostart
 @opindex no-autostart
@@ -2231,6 +2288,14 @@ allow to convey suitable information for elliptic curves.
 Same as the command @option{--fingerprint} but changes only the format
 of the output and may be used together with another command.
 
+@item --with-subkey-fingerprint
+@opindex with-subkey-fingerprint
+If a fingerprint is printed for the primary key, this option forces
+printing of the fingerprint for all subkeys.  This could also be
+achieved by using the @option{--with-fingerprint} twice but by using
+this option along with keyid-format "none" a compact fingerprint is
+printed.
+
 @item --with-icao-spelling
 @opindex with-icao-spelling
 Print the ICAO spelling of the fingerprint in addition to the hex digits.
@@ -2290,6 +2355,14 @@ Disable the use of the modification detection code. Note that by
 using this option, the encrypted message becomes vulnerable to a
 message modification attack.
 
+@item --disable-signer-uid
+@opindex disable-signer-uid
+By default the user ID of the signing key is embedded in the data
+signature.  As of now this is only done if the signing key has been
+specified with @option{local-user} using a mail address.  This
+information can be helpful for verifier to locate the key; see
+option @option{--auto-key-retrieve}.
+
 @item --personal-cipher-preferences @code{string}
 @opindex personal-cipher-preferences
 Set the list of personal cipher preferences to @code{string}.  Use
@@ -3088,7 +3161,7 @@ current home directory (@pxref{option --homedir}).
 @table @file
 
   @item gpg.conf
-  @cindex gpg.conf
+  @efindex gpg.conf
   This is the standard configuration file read by @command{@gpgname} on
   startup.  It may contain any valid long option; the leading two dashes
   may not be entered and the option may not be abbreviated.  This default
@@ -3110,13 +3183,21 @@ files; They all live in in the current home directory (@pxref{option
 
 
 @table @file
+  @item ~/.gnupg
+  @efindex ~/.gnupg
+  This is the default home directory which is used if neither the
+  environment variable @code{GNUPGHOME} nor the option
+  @option{--homedir} is given.
+
   @item ~/.gnupg/pubring.gpg
+  @efindex pubring.gpg
   The public keyring.  You should backup this file.
 
   @item ~/.gnupg/pubring.gpg.lock
   The lock file for the public keyring.
 
   @item ~/.gnupg/pubring.kbx
+  @efindex pubring.kbx
   The public keyring using a different format.  This file is sharred
   with @command{gpgsm}.  You should backup this file.
 
@@ -3124,13 +3205,19 @@ files; They all live in in the current home directory (@pxref{option
   The lock file for @file{pubring.kbx}.
 
   @item ~/.gnupg/secring.gpg
+  @efindex secring.gpg
   A secret keyring as used by GnuPG versions before 2.1.  It is not
   used by GnuPG 2.1 and later.
 
+  @item ~/.gnupg/secring.gpg.lock
+  The lock file for the secret keyring.
+
   @item ~/.gnupg/.gpg-v21-migrated
+  @efindex .gpg-v21-migrated
   File indicating that a migration to GnuPG 2.1 has been done.
 
   @item ~/.gnupg/trustdb.gpg
+  @efindex trustdb.gpg
   The trust database.  There is no need to backup this file; it is better
   to backup the ownertrust values (@pxref{option --export-ownertrust}).
 
@@ -3138,12 +3225,11 @@ files; They all live in in the current home directory (@pxref{option
   The lock file for the trust database.
 
   @item ~/.gnupg/random_seed
+  @efindex random_seed
   A file used to preserve the state of the internal random pool.
 
-  @item ~/.gnupg/secring.gpg.lock
-  The lock file for the secret keyring.
-
   @item ~/.gnupg/openpgp-revocs.d/
+  @efindex openpgp-revocs.d
   This is the directory where gpg stores pre-generated revocation
   certificates.  The file name corresponds to the OpenPGP fingerprint of
   the respective key.  It is suggested to backup those certificates and
@@ -3154,11 +3240,9 @@ files; They all live in in the current home directory (@pxref{option
   this backup closed away.
 
   @item @value{DATADIR}/options.skel
+  @efindex options.skel
   The skeleton options file.
 
-  @item @value{LIBDIR}/
-  Default location for extensions.
-
 @end table
 
 @c man:.RE
@@ -3167,24 +3251,29 @@ Operation is further controlled by a few environment variables:
 @table @asis
 
   @item HOME
+  @efindex HOME
   Used to locate the default home directory.
 
   @item GNUPGHOME
+  @efindex GNUPGHOME
   If set directory used instead of "~/.gnupg".
 
   @item GPG_AGENT_INFO
-  This variable was used by GnuPG versions before 2.1
+  This variable is obsolete; it was used by GnuPG versions before 2.1.
 
   @item PINENTRY_USER_DATA
+  @efindex PINENTRY_USER_DATA
   This value is passed via gpg-agent to pinentry.  It is useful to convey
   extra information to a custom pinentry.
 
   @item COLUMNS
   @itemx LINES
+  @efindex COLUMNS
+  @efindex LINES
   Used to size some displays to the full size of the screen.
 
-
   @item LANGUAGE
+  @efindex LANGUAGE
   Apart from its use by GNU, it is used in the W32 version to override the
   language selection done through the Registry.  If used and set to a
   valid and available language name (@var{langid}), the file with the
index b585975..2f6c297 100644 (file)
@@ -357,9 +357,7 @@ suite hack and may thus not be used in the file name.
 @item --dirmngr-program @var{file}
 @opindex dirmngr-program
 Specify a dirmngr program to be used for @acronym{CRL} checks.  The
-default value is @file{@value{BINDIR}/dirmngr}.  This is only used as a
-fallback when the environment variable @code{DIRMNGR_INFO} is not set or
-a running dirmngr cannot be connected.
+default value is @file{@value{BINDIR}/dirmngr}.
 
 @item --prefer-system-dirmngr
 @opindex prefer-system-dirmngr
@@ -800,7 +798,7 @@ current home directory (@pxref{option --homedir}).
 @table @file
 
 @item gpgsm.conf
-@cindex gpgsm.conf
+@efindex gpgsm.conf
 This is the standard configuration file read by @command{gpgsm} on
 startup.  It may contain any valid long option; the leading two dashes
 may not be entered and the option may not be abbreviated.  This default
@@ -809,7 +807,7 @@ You should backup this file.
 
 
 @item policies.txt
-@cindex policies.txt
+@efindex policies.txt
 This is a list of allowed CA policies.  This file should list the
 object identifiers of the policies line by line.  Empty lines and
 lines starting with a hash mark are ignored.  Policies missing in this
@@ -829,7 +827,7 @@ like this:
 @c man:.RE
 
 @item qualified.txt
-@cindex qualified.txt
+@efindex qualified.txt
 This is the list of root certificates used for qualified certificates.
 They are defined as certificates capable of creating legally binding
 signatures in the same way as handwritten signatures are.  Comments
@@ -865,7 +863,7 @@ Because this software has not yet been approved for use with such
 certificates, appropriate notices will be shown to indicate this fact.
 
 @item help.txt
-@cindex help.txt
+@efindex help.txt
 This is plain text file with a few help entries used with
 @command{pinentry} as well as a large list of help items for
 @command{gpg} and @command{gpgsm}.  The standard file has English help
@@ -879,7 +877,7 @@ For a reference of the help file's syntax, please see the installed
 
 
 @item com-certs.pem
-@cindex com-certs.pem
+@efindex com-certs.pem
 This file is a collection of common certificates used to populated a
 newly created @file{pubring.kbx}.  An administrator may replace this
 file with a custom one.  The format is a concatenation of PEM encoded
@@ -901,20 +899,20 @@ they all live in in the current home directory (@pxref{option
 
 @table @file
 @item pubring.kbx
-@cindex pubring.kbx
+@efindex pubring.kbx
 This a database file storing the certificates as well as meta
 information.  For debugging purposes the tool @command{kbxutil} may be
 used to show the internal structure of this file.  You should backup
 this file.
 
 @item random_seed
-@cindex random_seed
+@efindex random_seed
 This content of this file is used to maintain the internal state of the
 random number generator across invocations.  The same file is used by
 other programs of this software too.
 
 @item S.gpg-agent
-@cindex S.gpg-agent
+@efindex S.gpg-agent
 If this file exists
 @command{gpgsm} will first try to connect to this socket for
 accessing @command{gpg-agent} before starting a new @command{gpg-agent}
@@ -1535,18 +1533,25 @@ set to the empty string, and if @code{<STRING>} is given it is set to
 that string.
 
 @item display
+@efindex DISPLAY
 Set the session environment variable @code{DISPLAY} is set to @var{value}.
 @item ttyname
+@efindex GPG_TTY
 Set the session environment variable @code{GPG_TTY} is set to @var{value}.
 @item ttytype
+@efindex TERM
 Set the session environment variable @code{TERM} is set to @var{value}.
 @item lc-ctype
+@efindex LC_CTYPE
 Set the session environment variable @code{LC_CTYPE} is set to @var{value}.
 @item lc-messages
+@efindex LC_MESSAGES
 Set the session environment variable @code{LC_MESSAGES} is set to @var{value}.
 @item xauthority
+@efindex XAUTHORITY
 Set the session environment variable @code{XAUTHORITY} is set to @var{value}.
 @item pinentry-user-data
+@efindex PINENTRY_USER_DATA
 Set the session environment variable @code{PINENTRY_USER_DATA} is set
 to @var{value}.
 
index 7bcce46..e1ce077 100644 (file)
@@ -1,6 +1,8 @@
 @c This option is included at several places.
 @item --homedir @var{dir}
 @opindex homedir
+@efindex GNUPGHOME
+@efindex HKCU\Software\GNU\GnuPG:HomeDir
 Set the name of the home directory to @var{dir}. If this option is not
 used, the home directory defaults to @file{~/.gnupg}.  It is only
 recognized when given on the command line.  It also overrides any home
@@ -12,6 +14,7 @@ On Windows systems it is possible to install GnuPG as a portable
 application.  In this case only this command line option is
 considered, all other ways to set a home directory are ignored.
 
+@efindex gpgconf.ctl
 To install GnuPG as a portable application under Windows, create an
 empty file name @file{gpgconf.ctl} in the same directory as the tool
 @file{gpgconf.exe}.  The root of the installation is than that
index 7f1058b..5e53223 100644 (file)
@@ -222,11 +222,12 @@ This option appends a thread ID to the PID in the log output.
 
 @item --debug-assuan-log-cats @var{cats}
 @opindex debug-assuan-log-cats
+@efindex ASSUAN_DEBUG
 Changes the active Libassuan logging categories to @var{cats}.  The
 value for @var{cats} is an unsigned integer given in usual C-Syntax.
 A value of of 0 switches to a default category.  If this option is not
 used the categories are taken from the environment variable
-@samp{ASSUAN_DEBUG}.  Note that this option has only an effect if the
+@code{ASSUAN_DEBUG}.  Note that this option has only an effect if the
 Assuan debug flag has also been with the option @option{--debug}.  For
 a list of categories see the Libassuan manual.
 
index a8cea87..dec07bd 100644 (file)
@@ -11,28 +11,6 @@ right now, however there are probably a lot of smaller glitches we need
 to fix first.  The major problem areas are:
 
 @itemize
-@item 
-For logging to sockets and other internal operations the
-@code{fopencookie} function (@code{funopen} under *BSD) is used.  This
-is a very convenient function which makes it possible to create outputs in
-a structures and easy maintainable way.  The drawback however is that
-most proprietary OSes don't support this function.  At g10@tie{}Code we
-have looked into several ways on how to overcome this limitation but no
-sufficiently easy and maintainable way has been found.  Porting
-@emph{glibc} to a general POSIX system is of course an option and would
-make writing portable software much easier; this it has not yet been
-done and the system administrator would need to cope with the GNU
-specific admin things in addition to the generic ones of his system.
-
-We have now settled to use explicit stdio wrappers with a functionality
-similar to funopen.  Although the code for this has already been written
-(@emph{libestream}), we have not yet changed GnuPG to use it.
-
-This means that on systems not supporting either @code{funopen} or
-@code{fopencookie}, logging to a socket won't work, prompts are not
-formatted as pretty as they should be and @command{gpgsm}'s
-@code{LISTKEYS} Assuan command does not work.
-
 @item
 We are planning to use file descriptor passing for interprocess
 communication.  This will allow us save a lot of resources and improve
@@ -78,9 +56,3 @@ The periodical smartcard status checking done by @command{scdaemon} is
 not yet supported.
 
 @end itemize
-
-
-
-
-
-
index 425790e..8fdaa96 100644 (file)
@@ -319,6 +319,17 @@ gpg-agent and scdaemon.  Components which don't support reloading are
 ignored.  Note that as of now reload and kill have the same effect for
 scdaemon.
 
+@item --create-socketdir
+@opindex create-socketdir
+Create a directory for sockets below /run/user or /var/run/user.  This
+is command is only required if a non default home directory is used
+and the /run based sockets shall be used.  For the default home
+directory GnUPG creates a directory on the fly.
+
+@item --remove-socketdir
+@opindex remove-socketdir
+Remove a directory created with command @option{--create-socketdir}.
+
 @end table
 
 
index 1634985..3de908c 100644 (file)
@@ -705,6 +705,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
     { "emph",    0, "\\fI", "\\fR" },
     { "w",       1 },
     { "c",       5 },
+    { "efindex", 1 },
     { "opindex", 1 },
     { "cpindex", 1 },
     { "cindex",  1 },
index 18a1b69..fc33e83 100644 (file)
@@ -74,7 +74,7 @@ trust_source = trustdb.c trustdb.h tdbdump.c tdbio.c tdbio.h
 endif
 
 if USE_TOFU
-tofu_source = tofu.h tofu.c sqlite.c sqlite.h
+tofu_source = tofu.h tofu.c gpgsql.c gpgsql.h
 else
 tofu_source =
 endif
index 9b64967..2745734 100644 (file)
@@ -301,6 +301,8 @@ write_fake_data (IOBUF out, gcry_mpi_t a)
 
   if (!a)
     return 0;
+  if (!gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    return 0; /* e.g. due to generating a key with wrong usage.  */
   p = gcry_mpi_get_opaque ( a, &n);
   if (!p)
     return 0; /* For example due to a read error in
@@ -329,7 +331,7 @@ do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
     }
   else
     {
-      write_header2( out, ctb, uid->len, 2 );
+      write_header2( out, ctb, uid->len, 0 );
       rc = iobuf_write( out, uid->name, uid->len );
     }
   return rc;
@@ -1277,8 +1279,9 @@ sig_to_notation(PKT_signature *sig)
 {
   const byte *p;
   size_t len;
-  int seq=0,crit;
-  struct notation *list=NULL;
+  int seq = 0;
+  int crit;
+  notation_t list = NULL;
 
   /* See RFC 4880, 5.2.3.16 for the format of notation data.  In
      short, a notation has:
@@ -1323,6 +1326,7 @@ sig_to_notation(PKT_signature *sig)
          n->value=xmalloc(n2+1);
          memcpy(n->value,&p[8+n1],n2);
          n->value[n2]='\0';
+          n->flags.human = 1;
        }
       else
         /* Binary data.  */
index c5bd694..a023654 100644 (file)
@@ -303,7 +303,6 @@ start_agent (ctrl_t ctrl, int for_card)
     {
       rc = start_new_gpg_agent (&agent_ctx,
                                 GPG_ERR_SOURCE_DEFAULT,
-                                opt.homedir,
                                 opt.agent_program,
                                 opt.lc_ctype, opt.lc_messages,
                                 opt.session_env,
@@ -1672,28 +1671,35 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
 
 
 \f
+struct keyinfo_data_parm_s
+{
+  char *serialno;
+  int cleartext;
+};
+
+
 static gpg_error_t
 keyinfo_status_cb (void *opaque, const char *line)
 {
-  char **serialno = opaque;
-  const char *s, *s2;
+  struct keyinfo_data_parm_s *data = opaque;
+  int is_smartcard;
+  char *s;
 
-  if ((s = has_leading_keyword (line, "KEYINFO")) && !*serialno)
+  if ((s = has_leading_keyword (line, "KEYINFO")) && data)
     {
-      s = strchr (s, ' ');
-      if (s && s[1] == 'T' && s[2] == ' ' && s[3])
+      /* Parse the arguments:
+       *      0        1        2        3       4          5
+       *   <keygrip> <type> <serialno> <idstr> <cached> <protection>
+       */
+      char *fields[6];
+
+      if (split_fields (s, fields, DIM (fields)) == 6)
         {
-          s += 3;
-          s2 = strchr (s, ' ');
-          if ( s2 > s )
-            {
-              *serialno = xtrymalloc ((s2 - s)+1);
-              if (*serialno)
-                {
-                  memcpy (*serialno, s, s2 - s);
-                  (*serialno)[s2 - s] = 0;
-                }
-            }
+          is_smartcard = (fields[1][0] == 'T');
+          if (is_smartcard && !data->serialno && strcmp (fields[2], "-"))
+            data->serialno = xtrystrdup (fields[2]);
+          /* 'P' for protected, 'C' for clear */
+          data->cleartext = (fields[5][0] == 'C');
         }
     }
   return 0;
@@ -1702,13 +1708,20 @@ keyinfo_status_cb (void *opaque, const char *line)
 
 /* Return the serial number for a secret key.  If the returned serial
    number is NULL, the key is not stored on a smartcard.  Caller needs
-   to free R_SERIALNO.  */
+   to free R_SERIALNO.
+
+   if r_cleartext is not NULL, the referenced int will be set to 1 if
+   the agent's copy of the key is stored in the clear, or 0 otherwise
+*/
 gpg_error_t
-agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
+                   char **r_serialno, int *r_cleartext)
 {
   gpg_error_t err;
   char line[ASSUAN_LINELENGTH];
-  char *serialno = NULL;
+  struct keyinfo_data_parm_s keyinfo;
+
+  memset (&keyinfo, 0,sizeof keyinfo);
 
   *r_serialno = NULL;
 
@@ -1723,17 +1736,21 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
   line[DIM(line)-1] = 0;
 
   err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
-                         keyinfo_status_cb, &serialno);
-  if (!err && serialno)
+                         keyinfo_status_cb, &keyinfo);
+  if (!err && keyinfo.serialno)
     {
       /* Sanity check for bad characters.  */
-      if (strpbrk (serialno, ":\n\r"))
+      if (strpbrk (keyinfo.serialno, ":\n\r"))
         err = GPG_ERR_INV_VALUE;
     }
   if (err)
-    xfree (serialno);
+    xfree (keyinfo.serialno);
   else
-    *r_serialno = serialno;
+    {
+      *r_serialno = keyinfo.serialno;
+      if (r_cleartext)
+        *r_cleartext = keyinfo.cleartext;
+    }
   return err;
 }
 
@@ -1805,7 +1822,7 @@ inq_genkey_parms (void *opaque, const char *line)
    PASSPHRASE is not NULL the agent is requested to protect the key
    with that passphrase instead of asking for one.  */
 gpg_error_t
-agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
+agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, char **passwd_nonce_addr,
               const char *keyparms, int no_protection,
               const char *passphrase, gcry_sexp_t *r_pubkey)
 {
@@ -1827,19 +1844,26 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
     return err;
   dfltparm.ctx = agent_ctx;
 
-  err = assuan_transact (agent_ctx, "RESET",
-                         NULL, NULL, NULL, NULL, NULL, NULL);
-  if (err)
-    return err;
+  if (passwd_nonce_addr && *passwd_nonce_addr)
+    ; /* A RESET would flush the passwd nonce cache.  */
+  else
+    {
+      err = assuan_transact (agent_ctx, "RESET",
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+      if (err)
+        return err;
+    }
 
   init_membuf (&data, 1024);
   gk_parm.dflt     = &dfltparm;
   gk_parm.keyparms = keyparms;
   gk_parm.passphrase = passphrase;
-  snprintf (line, sizeof line, "GENKEY%s%s%s",
+  snprintf (line, sizeof line, "GENKEY%s%s%s%s%s",
             no_protection? " --no-protection" :
             passphrase   ? " --inq-passwd" :
             /*          */ "",
+            passwd_nonce_addr && *passwd_nonce_addr? " --passwd-nonce=":"",
+            passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
             cache_nonce_addr && *cache_nonce_addr? " ":"",
             cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"");
   cn_parm.cache_nonce_addr = cache_nonce_addr;
@@ -2284,13 +2308,15 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
 \f
 /* Receive a secret key from the agent.  HEXKEYGRIP is the hexified
    keygrip, DESC a prompt to be displayed with the agent's passphrase
-   question (needs to be plus+percent escaped).  If CACHE_NONCE_ADDR
-   is not NULL the agent is advised to first try a passphrase
-   associated with that nonce.  On success the key is stored as a
-   canonical S-expression at R_RESULT and R_RESULTLEN.  */
+   question (needs to be plus+percent escaped).  if OPENPGP_PROTECTED
+   is not zero, ensure that the key material is returned in RFC
+   4880-compatible passphrased-protected form.  If CACHE_NONCE_ADDR is
+   not NULL the agent is advised to first try a passphrase associated
+   with that nonce.  On success the key is stored as a canonical
+   S-expression at R_RESULT and R_RESULTLEN.  */
 gpg_error_t
 agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
-                  char **cache_nonce_addr,
+                  int openpgp_protected, char **cache_nonce_addr,
                   unsigned char **r_result, size_t *r_resultlen)
 {
   gpg_error_t err;
@@ -2320,7 +2346,8 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
         return err;
     }
 
-  snprintf (line, DIM(line)-1, "EXPORT_KEY --openpgp %s%s %s",
+  snprintf (line, DIM(line)-1, "EXPORT_KEY %s%s%s %s",
+            openpgp_protected ? "--openpgp ":"",
             cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
             cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
             hexkeygrip);
@@ -2349,9 +2376,11 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
 \f
 /* Ask the agent to delete the key identified by HEXKEYGRIP.  If DESC
    is not NULL, display DESC instead of the default description
-   message.  */
+   message.  If FORCE is true the agent is advised not to ask for
+   confirmation. */
 gpg_error_t
-agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
+agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+                  int force)
 {
   gpg_error_t err;
   char line[ASSUAN_LINELENGTH];
@@ -2376,7 +2405,8 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
         return err;
     }
 
-  snprintf (line, DIM(line)-1, "DELETE_KEY %s", hexkeygrip);
+  snprintf (line, DIM(line)-1, "DELETE_KEY%s %s",
+            force? " --force":"", hexkeygrip);
   err = assuan_transact (agent_ctx, line, NULL, NULL,
                          default_inq_cb, &dfltparm,
                          NULL, NULL);
@@ -2386,13 +2416,14 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
 
 \f
 /* Ask the agent to change the passphrase of the key identified by
-   HEXKEYGRIP.  If DESC is not NULL, display DESC instead of the
-   default description message.  If CACHE_NONCE_ADDR is not NULL the
-   agent is advised to first try a passphrase associated with that
-   nonce.  If PASSWD_NONCE_ADDR is not NULL the agent will try to use
-   the passphrase associated with that nonce.  */
+ * HEXKEYGRIP.  If DESC is not NULL, display DESC instead of the
+ * default description message.  If CACHE_NONCE_ADDR is not NULL the
+ * agent is advised to first try a passphrase associated with that
+ * nonce.  If PASSWD_NONCE_ADDR is not NULL the agent will try to use
+ * the passphrase associated with that nonce for the new passphrase.
+ * If VERIFY is true the passphrase is only verified.  */
 gpg_error_t
-agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify,
               char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
@@ -2411,7 +2442,6 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   if (!hexkeygrip || strlen (hexkeygrip) != 40)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-
   if (desc)
     {
       snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
@@ -2421,12 +2451,18 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
         return err;
     }
 
-  snprintf (line, DIM(line)-1, "PASSWD %s%s %s%s %s",
-            cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
-            cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
-            passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
-            passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
-            hexkeygrip);
+  if (verify)
+    snprintf (line, DIM(line)-1, "PASSWD %s%s --verify %s",
+              cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+              cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+              hexkeygrip);
+  else
+    snprintf (line, DIM(line)-1, "PASSWD %s%s %s%s %s",
+              cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+              cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+              passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
+              passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
+              hexkeygrip);
   cn_parm.cache_nonce_addr = cache_nonce_addr;
   cn_parm.passwd_nonce_addr = passwd_nonce_addr;
   err = assuan_transact (agent_ctx, line, NULL, NULL,
@@ -2435,6 +2471,7 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   return err;
 }
 
+
 /* Return the version reported by gpg-agent.  */
 gpg_error_t
 agent_get_version (ctrl_t ctrl, char **r_version)
index 208b75b..d85a6fd 100644 (file)
@@ -153,10 +153,11 @@ gpg_error_t agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock);
 
 /* Return infos about the secret key with HEXKEYGRIP.  */
 gpg_error_t agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
-                               char **r_serialno);
+                               char **r_serialno, int *r_cleartext);
 
 /* Generate a new key.  */
-gpg_error_t agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
+gpg_error_t agent_genkey (ctrl_t ctrl,
+                          char **cache_nonce_addr, char **passwd_nonce_addr,
                           const char *keyparms, int no_protection,
                           const char *passphrase,
                           gcry_sexp_t *r_pubkey);
@@ -191,15 +192,17 @@ gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc,
 
 /* Receive a key from the agent.  */
 gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip,
-                              const char *desc, char **cache_nonce_addr,
+                              const char *desc, int openpgp_protected,
+                              char **cache_nonce_addr,
                               unsigned char **r_result, size_t *r_resultlen);
 
 /* Delete a key from the agent.  */
 gpg_error_t agent_delete_key (ctrl_t ctrl, const char *hexkeygrip,
-                              const char *desc);
+                              const char *desc, int force);
 
 /* Change the passphrase of a key.  */
 gpg_error_t agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+                          int verify,
                           char **cache_nonce_addr, char **passwd_nonce_addr);
 /* Get the version reported by gpg-agent.  */
 gpg_error_t agent_get_version (ctrl_t ctrl, char **r_version);
index d35a5cf..75a7f46 100644 (file)
@@ -177,7 +177,6 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
   *r_ctx = NULL;
   err = start_new_dirmngr (&ctx,
                            GPG_ERR_SOURCE_DEFAULT,
-                           opt.homedir,
                            opt.dirmngr_program,
                            opt.autostart, opt.verbose, DBG_IPC,
                            NULL /*gpg_status2*/, ctrl);
index f76277c..966c571 100644 (file)
@@ -184,8 +184,14 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
               prompt = gpg_format_keydesc (node->pkt->pkt.public_key,
                                            FORMAT_KEYDESC_DELKEY, 1);
               err = hexkeygrip_from_pk (node->pkt->pkt.public_key, &hexgrip);
+              /* NB: We require --yes to advise the agent not to
+               * request a confirmation.  The rationale for this extra
+               * pre-caution is that since 2.1 the secret key may also
+               * be used for other protocols and thus deleting it from
+               * the gpg would also delete the key for other tools. */
               if (!err)
-                err = agent_delete_key (NULL, hexgrip, prompt);
+                err = agent_delete_key (NULL, hexgrip, prompt,
+                                        opt.answer_yes);
               xfree (prompt);
               xfree (hexgrip);
               if (err)
index 89604b4..b067376 100644 (file)
@@ -391,6 +391,78 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
 }
 
 
+/* Return an error if the key represented by the S-expression S_KEY
+ * and the OpenPGP key represented by PK do not use the same curve. */
+static gpg_error_t
+match_curve_skey_pk (gcry_sexp_t s_key, PKT_public_key *pk)
+{
+  gcry_sexp_t curve = NULL;
+  gcry_sexp_t flags = NULL;
+  char *curve_str = NULL;
+  char *flag;
+  const char *oidstr = NULL;
+  gcry_mpi_t curve_as_mpi = NULL;
+  gpg_error_t err;
+  int is_eddsa = 0;
+  int idx = 0;
+
+  if (!(pk->pubkey_algo==PUBKEY_ALGO_ECDH
+        || pk->pubkey_algo==PUBKEY_ALGO_ECDSA
+        || pk->pubkey_algo==PUBKEY_ALGO_EDDSA))
+    return gpg_error (GPG_ERR_PUBKEY_ALGO);
+
+  curve = gcry_sexp_find_token (s_key, "curve", 0);
+  if (!curve)
+    {
+      log_error ("no reported curve\n");
+      return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+    }
+  curve_str = gcry_sexp_nth_string (curve, 1);
+  gcry_sexp_release (curve); curve = NULL;
+  if (!curve_str)
+    {
+      log_error ("no curve name\n");
+      return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+    }
+  oidstr = openpgp_curve_to_oid (curve_str, NULL);
+  if (!oidstr)
+    {
+      log_error ("no OID known for curve '%s'\n", curve_str);
+      xfree (curve_str);
+      return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+    }
+  xfree (curve_str);
+  err = openpgp_oid_from_str (oidstr, &curve_as_mpi);
+  if (err)
+    return err;
+  if (gcry_mpi_cmp (pk->pkey[0], curve_as_mpi))
+    {
+      log_error ("curves do not match\n");
+      gcry_mpi_release (curve_as_mpi);
+      return gpg_error (GPG_ERR_INV_CURVE);
+    }
+  gcry_mpi_release (curve_as_mpi);
+  flags = gcry_sexp_find_token (s_key, "flags", 0);
+  if (flags)
+    {
+      for (idx = 1; idx < gcry_sexp_length (flags); idx++)
+        {
+          flag = gcry_sexp_nth_string (flags, idx);
+          if (flag && (strcmp ("eddsa", flag) == 0))
+            is_eddsa = 1;
+          gcry_free (flag);
+        }
+    }
+  if (is_eddsa != (pk->pubkey_algo == PUBKEY_ALGO_EDDSA))
+    {
+      log_error ("disagreement about EdDSA\n");
+      err = gpg_error (GPG_ERR_INV_CURVE);
+    }
+
+  return err;
+}
+
+
 /* Return a canonicalized public key algoithms.  This is used to
    compare different flavors of algorithms (e.g. ELG and ELG_E are
    considered the same).  */
@@ -412,6 +484,175 @@ canon_pk_algo (enum gcry_pk_algos algo)
 }
 
 
+/* Take a cleartext dump of a secret key in PK and change the
+ * parameter array in PK to include the secret parameters.  */
+static gpg_error_t
+cleartext_secret_key_to_openpgp (gcry_sexp_t s_key, PKT_public_key *pk)
+{
+  gpg_error_t err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  gcry_sexp_t top_list;
+  gcry_sexp_t key = NULL;
+  char *key_type = NULL;
+  enum gcry_pk_algos pk_algo;
+  struct seckey_info *ski;
+  int idx, sec_start;
+  gcry_mpi_t pub_params[10] = { NULL };
+
+  /* we look for a private-key, then the first element in it tells us
+     the type */
+  top_list = gcry_sexp_find_token (s_key, "private-key", 0);
+  if (!top_list)
+    goto bad_seckey;
+  if (gcry_sexp_length(top_list) != 2)
+    goto bad_seckey;
+  key = gcry_sexp_nth (top_list, 1);
+  if (!key)
+    goto bad_seckey;
+  key_type = gcry_sexp_nth_string(key, 0);
+  pk_algo = gcry_pk_map_name (key_type);
+
+  log_assert (!pk->seckey_info);
+
+  pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
+  if (!ski)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  switch (canon_pk_algo (pk_algo))
+    {
+    case GCRY_PK_RSA:
+      if (!is_RSA (pk->pubkey_algo))
+        goto bad_pubkey_algo;
+      err = gcry_sexp_extract_param (key, NULL, "ne",
+                                     &pub_params[0],
+                                     &pub_params[1],
+                                     NULL);
+      for (idx=0; idx < 2 && !err; idx++)
+        if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx]))
+          err = gpg_error (GPG_ERR_BAD_PUBKEY);
+      if (!err)
+        {
+          for (idx = 2; idx < 6 && !err; idx++)
+            {
+              gcry_mpi_release (pk->pkey[idx]);
+              pk->pkey[idx] = NULL;
+            }
+          err = gcry_sexp_extract_param (key, NULL, "dpqu",
+                                         &pk->pkey[2],
+                                         &pk->pkey[3],
+                                         &pk->pkey[4],
+                                         &pk->pkey[5],
+                                         NULL);
+        }
+      if (!err)
+        {
+          for (idx = 2; idx < 6; idx++)
+            ski->csum += checksum_mpi (pk->pkey[idx]);
+        }
+      break;
+
+    case GCRY_PK_DSA:
+      if (!is_DSA (pk->pubkey_algo))
+        goto bad_pubkey_algo;
+      err = gcry_sexp_extract_param (key, NULL, "pqgy",
+                                     &pub_params[0],
+                                     &pub_params[1],
+                                     &pub_params[2],
+                                     &pub_params[3],
+                                     NULL);
+      for (idx=0; idx < 4 && !err; idx++)
+        if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx]))
+          err = gpg_error (GPG_ERR_BAD_PUBKEY);
+      if (!err)
+        {
+          gcry_mpi_release (pk->pkey[4]);
+          pk->pkey[4] = NULL;
+          err = gcry_sexp_extract_param (key, NULL, "x",
+                                         &pk->pkey[4],
+                                         NULL);
+        }
+      if (!err)
+        ski->csum += checksum_mpi (pk->pkey[4]);
+      break;
+
+    case GCRY_PK_ELG:
+      if (!is_ELGAMAL (pk->pubkey_algo))
+        goto bad_pubkey_algo;
+      err = gcry_sexp_extract_param (key, NULL, "pgy",
+                                     &pub_params[0],
+                                     &pub_params[1],
+                                     &pub_params[2],
+                                     NULL);
+      for (idx=0; idx < 3 && !err; idx++)
+        if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx]))
+          err = gpg_error (GPG_ERR_BAD_PUBKEY);
+      if (!err)
+        {
+          gcry_mpi_release (pk->pkey[3]);
+          pk->pkey[3] = NULL;
+          err = gcry_sexp_extract_param (key, NULL, "x",
+                                         &pk->pkey[3],
+                                         NULL);
+        }
+      if (!err)
+        ski->csum += checksum_mpi (pk->pkey[3]);
+      break;
+
+    case GCRY_PK_ECC:
+      err = match_curve_skey_pk (key, pk);
+      if (err)
+        goto leave;
+      if (!err)
+        err = gcry_sexp_extract_param (key, NULL, "q",
+                                       &pub_params[0],
+                                       NULL);
+      if (!err && (gcry_mpi_cmp(pk->pkey[1], pub_params[0])))
+        err = gpg_error (GPG_ERR_BAD_PUBKEY);
+
+      sec_start = 2;
+      if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
+        sec_start += 1;
+      if (!err)
+        {
+          gcry_mpi_release (pk->pkey[sec_start]);
+          pk->pkey[sec_start] = NULL;
+          err = gcry_sexp_extract_param (key, NULL, "d",
+                                         &pk->pkey[sec_start],
+                                         NULL);
+        }
+
+      if (!err)
+        ski->csum += checksum_mpi (pk->pkey[sec_start]);
+      break;
+
+    default:
+      pk->seckey_info = NULL;
+      xfree (ski);
+      err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+      break;
+    }
+
+ leave:
+  gcry_sexp_release (top_list);
+  gcry_sexp_release (key);
+  gcry_free (key_type);
+
+  for (idx=0; idx < DIM(pub_params); idx++)
+    gcry_mpi_release (pub_params[idx]);
+  return err;
+
+ bad_pubkey_algo:
+  err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+  goto leave;
+
+ bad_seckey:
+  err = gpg_error (GPG_ERR_BAD_SECKEY);
+  goto leave;
+}
+
+
 /* Use the key transfer format given in S_PGP to create the secinfo
    structure in PK and change the parameter array in PK to include the
    secret parameters.  */
@@ -831,12 +1072,17 @@ print_status_exported (PKT_public_key *pk)
  *
  * Since the key data from agant is encrypted, decrypt it by CIPHERHD.
  * Then, parse the decrypted key data in transfer format, and put
- * secret papameters into PK.
+ * secret parameters into PK.
+ *
+ * If CLEARTEXT is 0, store the secret key material
+ * passphrase-protected.  Otherwise, store secret key material in the
+ * clear.
  *
  * CACHE_NONCE_ADDR is used to share nonce for multple key retrievals.
  */
 gpg_error_t
 receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
+                           int cleartext,
                            char **cache_nonce_addr, const char *hexgrip,
                            PKT_public_key *pk)
 {
@@ -852,7 +1098,7 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
     log_info ("key %s: asking agent for the secret parts\n", hexgrip);
 
   prompt = gpg_format_keydesc (pk, FORMAT_KEYDESC_EXPORT,1);
-  err = agent_export_key (ctrl, hexgrip, prompt, cache_nonce_addr,
+  err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, cache_nonce_addr,
                           &wrappedkey, &wrappedkeylen);
   xfree (prompt);
 
@@ -880,7 +1126,10 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
   err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
   if (!err)
     {
-      err = transfer_format_to_openpgp (s_skey, pk);
+      if (cleartext)
+        err = cleartext_secret_key_to_openpgp (s_skey, pk);
+      else
+        err = transfer_format_to_openpgp (s_skey, pk);
       gcry_sexp_release (s_skey);
     }
 
@@ -924,6 +1173,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   gcry_cipher_hd_t cipherhd = NULL;
   char *cache_nonce = NULL;
   struct export_stats_s dummystats;
+  int cleartext = 0;
 
   if (!stats)
     stats = &dummystats;
@@ -1228,7 +1478,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                   serialno = NULL;
                 }
               else
-                err = agent_get_keyinfo (ctrl, hexgrip, &serialno);
+                err = agent_get_keyinfo (ctrl, hexgrip, &serialno, &cleartext);
 
               if ((!err && serialno)
                   && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
@@ -1276,7 +1526,8 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                 }
               else if (!err)
                 {
-                  err = receive_seckey_from_agent (ctrl, cipherhd, &cache_nonce,
+                  err = receive_seckey_from_agent (ctrl, cipherhd,
+                                                   cleartext, &cache_nonce,
                                                    hexgrip, pk);
                   if (err)
                     {
index 8176e36..3883f87 100644 (file)
@@ -82,6 +82,7 @@ free_seckey_enc( PKT_signature *sig )
       xfree (sig->pka_info->uri);
       xfree (sig->pka_info);
     }
+  xfree (sig->signers_uid);
 
   xfree(sig);
 }
@@ -258,6 +259,8 @@ copy_signature( PKT_signature *d, PKT_signature *s )
     d->pka_info = s->pka_info? cp_pka_info (s->pka_info) : NULL;
     d->hashed = cp_subpktarea (s->hashed);
     d->unhashed = cp_subpktarea (s->unhashed);
+    if (s->signers_uid)
+      d->signers_uid = xstrdup (s->signers_uid);
     if(s->numrevkeys)
       {
        d->revkey=NULL;
index 907007b..ad0148e 100644 (file)
@@ -38,6 +38,7 @@
 #include "call-agent.h"
 #include "host2net.h"
 #include "mbox-util.h"
+#include "status.h"
 
 #define MAX_PK_CACHE_ENTRIES   PK_UID_CACHE_SIZE
 #define MAX_UID_CACHE_ENTRIES  PK_UID_CACHE_SIZE
 #error We need the cache for key creation
 #endif
 
+/* Flags values returned by the lookup code.  Note that the values are
+ * directly used by the KEY_CONSIDERED status line.  */
+#define LOOKUP_NOT_SELECTED        (1<<0)
+#define LOOKUP_ALL_SUBKEYS_EXPIRED (1<<1)  /* or revoked */
+
+
+/* A context object used by the lookup functions.  */
 struct getkey_ctx_s
 {
   /* Part of the search criteria: whether the search is an exact
@@ -3045,51 +3053,54 @@ merge_selfsigs (KBNODE keyblock)
 
 \f
 /* See whether the key satisfies any additional requirements specified
-   in CTX.  If so, return 1 and set CTX->FOUND_KEY to an appropriate
-   key or subkey.  Otherwise, return 0 if there was no appropriate
-   key.
-
-   In case the primary key is not required, select a suitable subkey.
-   We need the primary key if PUBKEY_USAGE_CERT is set in
-   CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
-   is set in CTX->REQ_USAGE.
-
-   If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
-   are set in CTX->REQ_USAGE, we filter by the key's function.
-   Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
-   we only return a key if it is (at least) either a signing or a
-   certification key.
-
-   If CTX->REQ_USAGE is set, then we reject any keys that are not good
-   (i.e., valid, not revoked, not expired, etc.).  This allows the
-   getkey functions to be used for plain key listings.
-
-   Sets the matched key's user id field (pk->user_id) to the user id
-   that matched the low-level search criteria or NULL.
-
-
-   This function needs to handle several different cases:
-
-    1. No requested usage and no primary key requested
-       Examples for this case are that we have a keyID to be used
-       for decrytion or verification.
-    2. No usage but primary key requested
-       This is the case for all functions which work on an
-       entire keyblock, e.g. for editing or listing
-    3. Usage and primary key requested
-       FXME
-    4. Usage but no primary key requested
-       FIXME
-
+ * in CTX.  If so, return 1 and set CTX->FOUND_KEY to an appropriate
+ * key or subkey.  Otherwise, return 0 if there was no appropriate
+ * key.
+ *
+ * In case the primary key is not required, select a suitable subkey.
+ * We need the primary key if PUBKEY_USAGE_CERT is set in
+ * CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
+ * is set in CTX->REQ_USAGE.
+ *
+ * If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
+ * are set in CTX->REQ_USAGE, we filter by the key's function.
+ * Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
+ * we only return a key if it is (at least) either a signing or a
+ * certification key.
+ *
+ * If CTX->REQ_USAGE is set, then we reject any keys that are not good
+ * (i.e., valid, not revoked, not expired, etc.).  This allows the
+ * getkey functions to be used for plain key listings.
+ *
+ * Sets the matched key's user id field (pk->user_id) to the user id
+ * that matched the low-level search criteria or NULL.  If R_FLAGS is
+ * not NULL set certain flags for more detailed error reporting.  Used
+ * flags are:
+ * - LOOKUP_ALL_SUBKEYS_EXPIRED :: All Subkeys are expired or have
+ *                                 been revoked.
+ *
+ * This function needs to handle several different cases:
+ *
+ *  1. No requested usage and no primary key requested
+ *     Examples for this case are that we have a keyID to be used
+ *     for decrytion or verification.
+ *  2. No usage but primary key requested
+ *     This is the case for all functions which work on an
+ *     entire keyblock, e.g. for editing or listing
+ *  3. Usage and primary key requested
+ *     FIXME
+ *  4. Usage but no primary key requested
+ *     FIXME
+ *
  */
-static KBNODE
-finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
+static kbnode_t
+finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
 {
-  KBNODE k;
+  kbnode_t k;
 
   /* If CTX->EXACT is set, the key or subkey that actually matched the
      low-level search criteria.  */
-  KBNODE foundk = NULL;
+  kbnode_t foundk = NULL;
   /* The user id (if any) that matched the low-level search criteria.  */
   PKT_user_id *foundu = NULL;
 
@@ -3100,21 +3111,23 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
      if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
      do not understand signatures made by a signing subkey.  PGP 8
      does. */
-  int req_prim = (ctx->req_usage & PUBKEY_USAGE_CERT) ||
-    ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG));
+  int req_prim = ((ctx->req_usage & PUBKEY_USAGE_CERT)
+                  || ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG)));
 
   u32 curtime = make_timestamp ();
 
   u32 latest_date;
-  KBNODE latest_key;
+  kbnode_t latest_key;
   PKT_public_key *pk;
 
-
   log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
+  if (r_flags)
+    *r_flags = 0;
+
+  /* For an exact match mark the primary or subkey that matched the
+     low-level search criteria.  */
   if (ctx->exact)
-    /* Get the key or subkey that matched the low-level search
-       criteria.  */
     {
       for (k = keyblock; k; k = k->next)
        {
@@ -3154,24 +3167,28 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
 
   latest_date = 0;
   latest_key = NULL;
-  /* Set latest_key to the latest (the one with the most recent
-     timestamp) good (valid, not revoked, not expired, etc.) subkey.
-
-     Don't bother if we are only looking for a primary key or we need
-     an exact match and the exact match is not a subkey.  */
+  /* Set LATEST_KEY to the latest (the one with the most recent
+   * timestamp) good (valid, not revoked, not expired, etc.) subkey.
+   *
+   * Don't bother if we are only looking for a primary key or we need
+   * an exact match and the exact match is not a subkey.  */
   if (req_prim || (foundk && foundk->pkt->pkttype != PKT_PUBLIC_SUBKEY))
     ;
   else
     {
-      KBNODE nextk;
+      kbnode_t nextk;
+      int n_subkeys = 0;
+      int n_revoked_or_expired = 0;
 
       /* Either start a loop or check just this one subkey.  */
       for (k = foundk ? foundk : keyblock; k; k = nextk)
        {
          if (foundk)
-           /* If FOUNDK is not NULL, then only consider that exact
-              key, i.e., don't iterate.  */
-           nextk = NULL;
+            {
+              /* If FOUNDK is not NULL, then only consider that exact
+                 key, i.e., don't iterate.  */
+              nextk = NULL;
+            }
          else
            nextk = k->next;
 
@@ -3182,24 +3199,35 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
          if (DBG_LOOKUP)
            log_debug ("\tchecking subkey %08lX\n",
                       (ulong) keyid_from_pk (pk, NULL));
+
          if (!pk->flags.valid)
            {
              if (DBG_LOOKUP)
                log_debug ("\tsubkey not valid\n");
              continue;
            }
+         if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
+           {
+             if (DBG_LOOKUP)
+               log_debug ("\tusage does not match: want=%x have=%x\n",
+                          req_usage, pk->pubkey_usage);
+             continue;
+           }
+
+          n_subkeys++;
          if (pk->flags.revoked)
            {
              if (DBG_LOOKUP)
                log_debug ("\tsubkey has been revoked\n");
+              n_revoked_or_expired++;
              continue;
            }
          if (pk->has_expired)
            {
              if (DBG_LOOKUP)
                log_debug ("\tsubkey has expired\n");
+              n_revoked_or_expired++;
              continue;
-
            }
          if (pk->timestamp > curtime && !opt.ignore_valid_from)
            {
@@ -3208,14 +3236,6 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
              continue;
            }
 
-         if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
-           {
-             if (DBG_LOOKUP)
-               log_debug ("\tusage does not match: want=%x have=%x\n",
-                          req_usage, pk->pubkey_usage);
-             continue;
-           }
-
          if (DBG_LOOKUP)
            log_debug ("\tsubkey might be fine\n");
          /* In case a key has a timestamp of 0 set, we make sure
@@ -3228,18 +3248,20 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
              latest_key = k;
            }
        }
+      if (n_subkeys == n_revoked_or_expired && r_flags)
+        *r_flags |= LOOKUP_ALL_SUBKEYS_EXPIRED;
     }
 
   /* Check if the primary key is ok (valid, not revoke, not expire,
-     matches requested usage) if:
-
-       - we didn't find an appropriate subkey and we're not doing an
-         exact search,
-
-       - we're doing an exact match and the exact match was the
-         primary key, or,
-
-       - we're just considering the primary key.  */
+   * matches requested usage) if:
+   *
+   *   - we didn't find an appropriate subkey and we're not doing an
+   *     exact search,
+   *
+   *   - we're doing an exact match and the exact match was the
+   *     primary key, or,
+   *
+   *   - we're just considering the primary key.  */
   if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
     {
       if (DBG_LOOKUP && !foundk && !req_prim)
@@ -3250,6 +3272,12 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
          if (DBG_LOOKUP)
            log_debug ("\tprimary key not valid\n");
        }
+      else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
+       {
+         if (DBG_LOOKUP)
+           log_debug ("\tprimary key usage does not match: "
+                      "want=%x have=%x\n", req_usage, pk->pubkey_usage);
+       }
       else if (pk->flags.revoked)
        {
          if (DBG_LOOKUP)
@@ -3260,12 +3288,6 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
          if (DBG_LOOKUP)
            log_debug ("\tprimary key has expired\n");
        }
-      else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
-       {
-         if (DBG_LOOKUP)
-           log_debug ("\tprimary key usage does not match: "
-                      "want=%x have=%x\n", req_usage, pk->pubkey_usage);
-       }
       else /* Okay.  */
        {
          if (DBG_LOOKUP)
@@ -3309,6 +3331,34 @@ found:
 }
 
 
+/* Print a KEY_CONSIDERED status line.  */
+static void
+print_status_key_considered (kbnode_t keyblock, unsigned int flags)
+{
+  char hexfpr[2*MAX_FINGERPRINT_LEN + 1];
+  kbnode_t node;
+  char flagbuf[20];
+
+  if (!is_status_enabled ())
+    return;
+
+  for (node=keyblock; node; node = node->next)
+    if (node->pkt->pkttype == PKT_PUBLIC_KEY
+        || node->pkt->pkttype == PKT_SECRET_KEY)
+      break;
+  if (!node)
+    {
+      log_error ("%s: keyblock w/o primary key\n", __func__);
+      return;
+    }
+
+  hexfingerprint (node->pkt->pkt.public_key, hexfpr, sizeof hexfpr);
+  snprintf (flagbuf, sizeof flagbuf, " %u", flags);
+  write_status_strings (STATUS_KEY_CONSIDERED, hexfpr, flagbuf, NULL);
+}
+
+
+
 /* A high-level function to lookup keys.
 
    This function builds on top of the low-level keydb API.  It first
@@ -3329,6 +3379,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
   int no_suitable_key = 0;
   KBNODE keyblock = NULL;
   KBNODE found_key = NULL;
+  unsigned int infoflags;
 
   if (ret_keyblock)
     *ret_keyblock = NULL;
@@ -3360,14 +3411,19 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
        * merge_selfsigs.  For secret keys, premerge transferred the
        * keys to the keyblock.  */
       merge_selfsigs (keyblock);
-      found_key = finish_lookup (ctx, keyblock);
+      found_key = finish_lookup (ctx, keyblock, &infoflags);
+      if (!found_key)
+        infoflags |= LOOKUP_NOT_SELECTED;
+      print_status_key_considered (keyblock, infoflags);
       if (found_key)
        {
          no_suitable_key = 0;
          goto found;
        }
       else
-       no_suitable_key = 1;
+        {
+          no_suitable_key = 1;
+        }
 
     skip:
       /* Release resources and continue search. */
@@ -3381,7 +3437,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
       keydb_disable_caching (ctx->kr_handle);
     }
 
-found:
+ found:
   if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
 
index 006c95b..1f2d416 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -117,6 +117,7 @@ enum cmd_and_opt_values
     aQuickSignKey,
     aQuickLSignKey,
     aQuickAddUid,
+    aQuickAddKey,
     aListConfig,
     aListGcryptConfig,
     aGPGConfList,
@@ -181,6 +182,7 @@ enum cmd_and_opt_values
     oNoAskCertLevel,
     oFingerprint,
     oWithFingerprint,
+    oWithSubkeyFingerprint,
     oWithICAOSpelling,
     oWithKeygrip,
     oWithSecret,
@@ -394,6 +396,7 @@ enum cmd_and_opt_values
     oWeakDigest,
     oUnwrap,
     oOnlySignTextIDs,
+    oDisableSignerUID,
 
     oNoop
   };
@@ -426,6 +429,7 @@ static ARGPARSE_OPTS opts[] = {
               N_("quickly generate a new key pair")),
   ARGPARSE_c (aQuickAddUid,  "quick-adduid",
               N_("quickly add a new user-id")),
+  ARGPARSE_c (aQuickAddKey,  "quick-addkey", "@"),
   ARGPARSE_c (aFullKeygen,  "full-gen-key" ,
               N_("full featured key pair generation")),
   ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
@@ -444,10 +448,10 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aPasswd,   "passwd",     N_("change a passphrase")),
   ARGPARSE_c (aDesigRevoke, "desig-revoke","@" ),
   ARGPARSE_c (aExport, "export"           , N_("export keys") ),
-  ARGPARSE_c (aSendKeys, "send-keys"     , N_("export keys to a key server") ),
-  ARGPARSE_c (aRecvKeys, "recv-keys"     , N_("import keys from a key server") ),
+  ARGPARSE_c (aSendKeys, "send-keys"     , N_("export keys to a keyserver") ),
+  ARGPARSE_c (aRecvKeys, "recv-keys"     , N_("import keys from a keyserver") ),
   ARGPARSE_c (aSearchKeys, "search-keys" ,
-              N_("search for keys on a key server") ),
+              N_("search for keys on a keyserver") ),
   ARGPARSE_c (aRefreshKeys, "refresh-keys",
               N_("update all keys from a keyserver")),
   ARGPARSE_c (aLocateKeys, "locate-keys", "@"),
@@ -547,6 +551,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oDisableMDC, "disable-mdc", "@"),
   ARGPARSE_s_n (oNoDisableMDC, "no-disable-mdc", "@"),
 
+  ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"),
+
   ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
   ARGPARSE_s_n (oInteractive, "interactive", N_("prompt before overwriting")),
 
@@ -718,6 +724,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oUtf8Strings,      "utf8-strings", "@"),
   ARGPARSE_s_n (oNoUtf8Strings, "no-utf8-strings", "@"),
   ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
+  ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprint", "@"),
+  ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"),
   ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
   ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
   ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
@@ -995,9 +1003,9 @@ my_strusage( int level )
 
       case 31: p = "\nHome: "; break;
 #ifndef __riscos__
-      case 32: p = opt.homedir; break;
+      case 32: p = gnupg_homedir (); break;
 #else /* __riscos__ */
-      case 32: p = make_filename(opt.homedir, NULL); break;
+      case 32: p = make_filename(gnupg_homedir (), NULL); break;
 #endif /* __riscos__ */
       case 33: p = _("\nSupported algorithms:\n"); break;
       case 34:
@@ -1175,18 +1183,6 @@ set_debug (const char *level)
 }
 
 
-
-/* We need the home directory also in some other directories, so make
-   sure that both variables are always in sync. */
-static void
-set_homedir (const char *dir)
-{
-  if (!dir)
-    dir = "";
-  opt.homedir = dir;
-}
-
-
 /* We set the screen dimensions for UI purposes.  Do not allow screens
    smaller than 80x24 for the sake of simplicity. */
 static void
@@ -1407,7 +1403,8 @@ check_permissions (const char *path, int item)
      could be rectified if the homedir itself had proper
      permissions. */
   if(item!=0 && homedir_cache>-1
-     && ascii_strncasecmp(opt.homedir,tmppath,strlen(opt.homedir))==0)
+     && !ascii_strncasecmp (gnupg_homedir (), tmppath,
+                            strlen (gnupg_homedir ())))
     {
       ret=homedir_cache;
       goto end;
@@ -2046,6 +2043,9 @@ gpg_init_default_ctrl (ctrl_t ctrl)
 static void
 gpg_deinit_default_ctrl (ctrl_t ctrl)
 {
+#ifdef USE_TOFU
+  tofu_closedbs (ctrl);
+#endif
   gpg_dirmngr_deinit_session_data (ctrl);
 }
 
@@ -2074,18 +2074,19 @@ get_default_configname (void)
            break;
        }
 
-      configname = make_filename (opt.homedir, name, NULL);
+      configname = make_filename (gnupg_homedir (), name, NULL);
     }
   while (access (configname, R_OK));
 
   xfree(name);
 
   if (! configname)
-    configname = make_filename (opt.homedir, GPG_NAME EXTSEP_S "conf", NULL);
+    configname = make_filename (gnupg_homedir (),
+                                GPG_NAME 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);
+      char *p = make_filename (gnupg_homedir (), "options", NULL);
       if (! access (p, R_OK))
        log_info (_("Note: old default options file '%s' ignored\n"), p);
       xfree (p);
@@ -2093,7 +2094,7 @@ get_default_configname (void)
   else
     {
       /* Use the old default only if it exists.  */
-      char *p = make_filename (opt.homedir, "options", NULL);
+      char *p = make_filename (gnupg_homedir (), "options", NULL);
       if (!access (p, R_OK))
        {
          xfree (configname);
@@ -2241,10 +2242,10 @@ main (int argc, char **argv)
     opt.mangle_dos_filenames = 0;
     opt.min_cert_level = 2;
     set_screen_dimensions ();
-    opt.keyid_format = KF_SHORT;
+    opt.keyid_format = KF_NONE;
     opt.def_sig_expire = "0";
     opt.def_cert_expire = "0";
-    set_homedir (default_homedir ());
+    gnupg_set_homedir (NULL);
     opt.passphrase_repeat = 1;
     opt.emit_version = 1; /* Limit to the major number.  */
     opt.weak_digests = NULL;
@@ -2273,7 +2274,7 @@ main (int argc, char **argv)
             opt.no_homedir_creation = 1;
           }
         else if( pargs.r_opt == oHomedir )
-           set_homedir ( pargs.r.ret_str );
+           gnupg_set_homedir (pargs.r.ret_str);
        else if( pargs.r_opt == oNoPermissionWarn )
            opt.no_perm_warn=1;
        else if (pargs.r_opt == oStrict )
@@ -2287,10 +2288,10 @@ main (int argc, char **argv)
     }
 
 #ifdef HAVE_DOSISH_SYSTEM
-    if ( strchr (opt.homedir,'\\') ) {
-        char *d, *buf = xmalloc (strlen (opt.homedir)+1);
-        const char *s = opt.homedir;
-        for (d=buf,s=opt.homedir; *s; s++)
+    if ( strchr (gnupg_homedir (), '\\') ) {
+      char *d, *buf = xmalloc (strlen (gnupg_homedir ())+1);
+      const char *s;
+      for (d=buf, s = gnupg_homedir (); *s; s++)
           {
             *d++ = *s == '\\'? '/': *s;
 #ifdef HAVE_W32_SYSTEM
@@ -2299,7 +2300,7 @@ main (int argc, char **argv)
 #endif
           }
         *d = 0;
-        set_homedir (buf);
+        gnupg_set_homedir (buf);
     }
 #endif
 
@@ -2336,7 +2337,7 @@ main (int argc, char **argv)
     pargs.flags= ARGPARSE_FLAG_KEEP;
 
     /* By this point we have a homedir, and cannot change it. */
-    check_permissions(opt.homedir,0);
+    check_permissions (gnupg_homedir (), 0);
 
   next_pass:
     if( configname ) {
@@ -2430,6 +2431,7 @@ main (int argc, char **argv)
          case aStore:
          case aQuickKeygen:
          case aQuickAddUid:
+         case aQuickAddKey:
          case aExportOwnerTrust:
          case aImportOwnerTrust:
           case aRebuildKeydbCaches:
@@ -2560,6 +2562,9 @@ main (int argc, char **argv)
             opt.with_fingerprint = 1;
             opt.fingerprint++;
             break;
+         case oWithSubkeyFingerprint:
+            opt.with_subkey_fingerprint = 1;
+            break;
          case oWithICAOSpelling:
             opt.with_icao_spelling = 1;
             break;
@@ -2797,6 +2802,9 @@ main (int argc, char **argv)
          case oNoForceMDC: opt.force_mdc = 0; break;
          case oDisableMDC: opt.disable_mdc = 1; break;
          case oNoDisableMDC: opt.disable_mdc = 0; break;
+
+          case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break;
+
          case oS2KMode:   opt.s2k_mode = pargs.r.ret_int; break;
          case oS2KDigest: s2k_digest_string = xstrdup(pargs.r.ret_str); break;
          case oS2KCipher: s2k_cipher_string = xstrdup(pargs.r.ret_str); break;
@@ -3142,12 +3150,6 @@ main (int argc, char **argv)
                  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 ",
-                          pargs.r_opt==oAutoKeyRetrieve?"auto-key-retrieve":
-                              "no-auto-key-retrieve");
                break;
          case oShowSessionKey: opt.show_session_key = 1; break;
          case oOverrideSessionKey:
@@ -3250,6 +3252,8 @@ main (int argc, char **argv)
              opt.keyid_format=KF_0xSHORT;
            else if(ascii_strcasecmp(pargs.r.ret_str,"0xlong")==0)
              opt.keyid_format=KF_0xLONG;
+           else if(ascii_strcasecmp(pargs.r.ret_str,"none")==0)
+             opt.keyid_format = KF_NONE;
            else
              log_error("unknown keyid-format '%s'\n",pargs.r.ret_str);
            break;
@@ -3654,7 +3658,7 @@ main (int argc, char **argv)
 
     /* Set the random seed file. */
     if( use_random_seed ) {
-       char *p = make_filename(opt.homedir, "random_seed", NULL );
+      char *p = make_filename (gnupg_homedir (), "random_seed", NULL );
        gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
         if (!access (p, F_OK))
           register_secured_file (p);
@@ -3772,6 +3776,7 @@ main (int argc, char **argv)
       case aDeleteSecretAndPublicKeys:
       case aQuickKeygen:
       case aQuickAddUid:
+      case aQuickAddKey:
       case aFullKeygen:
       case aKeygen:
       case aImport:
@@ -4089,11 +4094,31 @@ main (int argc, char **argv)
        break;
 
       case aQuickKeygen:
-        if (argc != 1 )
-          wrong_args("--gen-key user-id");
-        username = make_username (fname);
-        quick_generate_keypair (ctrl, username);
-        xfree (username);
+        {
+          const char *x_algo, *x_usage, *x_expire;
+
+          if (argc < 1 || argc > 4)
+            wrong_args("--quick-gen-key USER-ID [ALGO [USAGE [EXPIRE]]]");
+          username = make_username (fname);
+          argv++, argc--;
+          x_algo = "";
+          x_usage = "";
+          x_expire = "";
+          if (argc)
+            {
+              x_algo = *argv++; argc--;
+              if (argc)
+                {
+                  x_usage = *argv++; argc--;
+                  if (argc)
+                    {
+                      x_expire = *argv++; argc--;
+                    }
+                }
+            }
+          quick_generate_keypair (ctrl, username, x_algo, x_usage, x_expire);
+          xfree (username);
+        }
         break;
 
       case aKeygen: /* generate a key */
@@ -4145,6 +4170,32 @@ main (int argc, char **argv)
         }
        break;
 
+      case aQuickAddKey:
+        {
+          const char *x_fpr, *x_algo, *x_usage, *x_expire;
+
+          if (argc < 1 || argc > 4)
+            wrong_args ("--quick-addkey FINGERPRINT [ALGO [USAGE [EXPIRE]]]");
+          x_fpr = *argv++; argc--;
+          x_algo = "";
+          x_usage = "";
+          x_expire = "";
+          if (argc)
+            {
+              x_algo = *argv++; argc--;
+              if (argc)
+                {
+                  x_usage = *argv++; argc--;
+                  if (argc)
+                   {
+                     x_expire = *argv++; argc--;
+                   }
+                }
+            }
+          keyedit_quick_addkey (ctrl, x_fpr, x_algo, x_usage, x_expire);
+        }
+       break;
+
       case aFastImport:
         opt.import_options |= IMPORT_FAST;
       case aImport:
@@ -4432,12 +4483,12 @@ main (int argc, char **argv)
       case aUpdateTrustDB:
        if( argc )
            wrong_args("--update-trustdb");
-       update_trustdb();
+       update_trustdb (ctrl);
        break;
 
       case aCheckTrustDB:
         /* Old versions allowed for arguments - ignore them */
-        check_trustdb();
+        check_trustdb (ctrl);
        break;
 
       case aFixTrustDB:
@@ -4586,7 +4637,7 @@ main (int argc, char **argv)
                }
 
              merge_keys_and_selfsig (kb);
-             if (tofu_set_policy (kb, policy))
+             if (tofu_set_policy (ctrl, kb, policy))
                g10_exit (1);
            }
 
index 5cd8366..c0f0a2d 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -63,6 +63,10 @@ typedef struct dirmngr_local_s *dirmngr_local_t;
 typedef struct kbnode_struct *KBNODE;
 typedef struct kbnode_struct *kbnode_t;
 
+/* TOFU database meta object.  */
+struct tofu_dbs_s;
+typedef struct tofu_dbs_s *tofu_dbs_t;
+
 
 /* Session control object.  This object is passed to most functions to
    convey the status of a session.  Note that the defaults are set by
@@ -74,6 +78,12 @@ struct server_control_s
 
   /* Local data for call-dirmngr.c  */
   dirmngr_local_t dirmngr_local;
+
+  /* Local data for tofu.c  */
+  struct {
+    tofu_dbs_t dbs;
+  } tofu;
+
 };
 
 
index d6f0307..cd5346f 100644 (file)
@@ -1509,10 +1509,10 @@ static struct option sig_options[] = {
     "that VALUE is a file to read the data from.  "
     "(RFC 4880, Section 5.2.3.16)" },
   { "--key-server-preferences", sig_big_endian_arg,
-    "Big-endian number encoding the key server preferences. "
+    "Big-endian number encoding the keyserver preferences. "
     "(RFC 4880, Section 5.2.3.17)" },
   { "--key-server", sig_string_arg,
-    "The preferred key server.  (RFC 4880, Section 5.2.3.18)" },
+    "The preferred keyserver.  (RFC 4880, Section 5.2.3.18)" },
   { "--primary-user-id", sig_flag,
     "Sets the primary user id flag.  (RFC 4880, Section 5.2.3.19)" },
   { "--policy-uri", sig_string_arg,
@@ -2956,10 +2956,6 @@ main (int argc, char *argv[])
   int processed;
   ctrl_t ctrl;
 
-  opt.homedir = default_homedir ();
-  if (! opt.homedir)
-    opt.homedir = "";
-
   opt.ignore_time_conflict = 1;
   /* Allow notations in the IETF space, for instance.  */
   opt.expert = 1;
similarity index 90%
rename from g10/sqlite.c
rename to g10/gpgsql.c
index 90490c2..72f51b5 100644 (file)
@@ -1,4 +1,4 @@
-/* sqlite.c - SQLite helper functions.
+/* gpgsql.c - SQLite helper functions.
  * Copyright (C) 2015 g10 Code GmbH
  *
  * This file is part of GnuPG.
 #include "util.h"
 #include "logging.h"
 
-#include "sqlite.h"
+#include "gpgsql.h"
 
 /* This is a convenience function that combines sqlite3_mprintf and
    sqlite3_exec.  */
 int
-sqlite3_exec_printf (sqlite3 *db,
-                    int (*callback)(void*,int,char**,char**), void *cookie,
-                    char **errmsg,
-                    const char *sql, ...)
+gpgsql_exec_printf (sqlite3 *db,
+                    int (*callback)(void*,int,char**,char**), void *cookie,
+                    char **errmsg,
+                    const char *sql, ...)
 {
   va_list ap;
   int rc;
@@ -56,12 +56,12 @@ sqlite3_exec_printf (sqlite3 *db,
 }
 
 int
-sqlite3_stepx (sqlite3 *db,
-               sqlite3_stmt **stmtp,
-               sqlite3_stepx_callback callback,
-               void *cookie,
-               char **errmsg,
-               const char *sql, ...)
+gpgsql_stepx (sqlite3 *db,
+              sqlite3_stmt **stmtp,
+              gpgsql_stepx_callback callback,
+              void *cookie,
+              char **errmsg,
+              const char *sql, ...)
 {
   int rc;
   int err = 0;
@@ -69,7 +69,7 @@ sqlite3_stepx (sqlite3 *db,
 
   va_list va;
   int args;
-  enum sqlite_arg_type t;
+  enum gpgsql_arg_type t;
   int i;
 
   int cols;
@@ -128,7 +128,7 @@ sqlite3_stepx (sqlite3 *db,
     {
       for (i = 1; i <= args; i ++)
         {
-          t = va_arg (va, enum sqlite_arg_type);
+          t = va_arg (va, enum gpgsql_arg_type);
           switch (t)
             {
             case SQLITE_ARG_INT:
@@ -169,7 +169,7 @@ sqlite3_stepx (sqlite3 *db,
         }
 
     }
-  t = va_arg (va, enum sqlite_arg_type);
+  t = va_arg (va, enum gpgsql_arg_type);
   log_assert (t == SQLITE_ARG_END);
   va_end (va);
 
diff --git a/g10/gpgsql.h b/g10/gpgsql.h
new file mode 100644 (file)
index 0000000..a540684
--- /dev/null
@@ -0,0 +1,61 @@
+/* gpgsql.h - SQLite helper functions.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_GPGSQL_H
+#define GNUPG_GPGSQL_H
+
+#include <sqlite3.h>
+
+enum gpgsql_arg_type
+  {
+    SQLITE_ARG_END = 0xdead001,
+    SQLITE_ARG_INT,
+    SQLITE_ARG_LONG_LONG,
+    SQLITE_ARG_STRING,
+    /* This takes two arguments: the blob as a void * and the length
+       of the blob as a long long.  */
+    SQLITE_ARG_BLOB
+  };
+
+int gpgsql_exec_printf (sqlite3 *db,
+                     int (*callback)(void*,int,char**,char**), void *cookie,
+                     char **errmsg,
+                     const char *sql, ...);
+
+typedef int (*gpgsql_stepx_callback) (void *cookie,
+                                      /* number of columns.  */
+                                      int cols,
+                                      /* columns as text.  */
+                                      char **values,
+                                      /* column names.  */
+                                      char **names,
+                                      /* The prepared statement so
+                                       * that it is possible to use
+                                       * something like
+                                       * sqlite3_column_blob().  */
+                                      sqlite3_stmt *statement);
+
+int gpgsql_stepx (sqlite3 *db,
+                  sqlite3_stmt **stmtp,
+                  gpgsql_stepx_callback callback,
+                  void *cookie,
+                  char **errmsg,
+                  const char *sql, ...);
+
+#endif /*GNUPG_GPGSQL_H*/
index 2a53e69..2aed10c 100644 (file)
@@ -79,7 +79,8 @@ static ARGPARSE_OPTS opts[] = {
                 N_("|FD|write status info to this FD")),
   ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
-  ARGPARSE_s_s (oWeakDigest, "weak-digest", "@"),
+  ARGPARSE_s_s (oWeakDigest, "weak-digest",
+                N_("|ALGO|reject signatures made with ALGO")),
 
   ARGPARSE_end ()
 };
@@ -168,7 +169,6 @@ main( int argc, char **argv )
   opt.trust_model = TM_ALWAYS;
   opt.batch = 1;
 
-  opt.homedir = default_homedir ();
   opt.weak_digests = NULL;
 
   tty_no_terminal(1);
@@ -195,7 +195,7 @@ main( int argc, char **argv )
         case oLoggerFD:
           log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1));
           break;
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oWeakDigest:
           additional_weak_digest(pargs.r.ret_str);
           break;
@@ -246,8 +246,9 @@ g10_exit( int rc )
  * this utility assumes that all keys in the keyring are trustworthy
  */
 int
-check_signatures_trust( PKT_signature *sig )
+check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
 {
+  (void)ctrl;
   (void)sig;
   return 0;
 }
@@ -279,22 +280,25 @@ cache_disabled_value(PKT_public_key *pk)
 }
 
 void
-check_trustdb_stale(void)
+check_trustdb_stale (ctrl_t ctrl)
 {
+  (void)ctrl;
 }
 
 int
-get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
+get_validity_info (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
 {
+  (void)ctrl;
   (void)pk;
   (void)uid;
   return '?';
 }
 
 unsigned int
-get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
-             int may_ask)
+get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
+              PKT_signature *sig, int may_ask)
 {
+  (void)ctrl;
   (void)pk;
   (void)uid;
   (void)sig;
@@ -310,8 +314,9 @@ trust_value_to_string (unsigned int value)
 }
 
 const char *
-uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid)
+uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid)
 {
+  (void)ctrl;
   (void)key;
   (void)uid;
   return "err";
@@ -598,10 +603,12 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
 }
 
 gpg_error_t
-agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
+                   char **r_serialno, int *r_cleartext)
 {
   (void)ctrl;
   (void)hexkeygrip;
+  (void)r_cleartext;
   *r_serialno = NULL;
   return gpg_error (GPG_ERR_NO_SECKEY);
 }
@@ -639,9 +646,10 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
 }
 
 gpg_error_t
-tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id,
                 enum tofu_policy *policy)
 {
+  (void)ctrl;
   (void)pk;
   (void)user_id;
   (void)policy;
index 6707797..7c0d1e2 100644 (file)
@@ -249,7 +249,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
      interactive or by not setting no-auto-check-trustdb */
 
   if (!(options & IMPORT_FAST))
-    check_or_update_trustdb ();
+    check_or_update_trustdb (ctrl);
 
   return rc;
 }
index 0164348..17ddd5d 100644 (file)
@@ -666,7 +666,7 @@ keydb_add_resource (const char *url, unsigned int flags)
           )
         filename = make_filename (resname, NULL);
       else
-        filename = make_filename (opt.homedir, resname, NULL);
+        filename = make_filename (gnupg_homedir (), resname, NULL);
     }
   else
     filename = xstrdup (resname);
index 8896eea..a30cf7a 100644 (file)
@@ -222,7 +222,7 @@ gpg_error_t keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
 
 /*-- pkclist.c --*/
 void show_revocation_reason( PKT_public_key *pk, int mode );
-int  check_signatures_trust( PKT_signature *sig );
+int  check_signatures_trust (ctrl_t ctrl, PKT_signature *sig);
 
 void release_pk_list (PK_LIST pk_list);
 int  build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
index 5461864..d05ea5d 100644 (file)
@@ -1,6 +1,6 @@
 /* keyedit.c - Edit properties of a key
  * Copyright (C) 1998-2010 Free Software Foundation, Inc.
- * Copyright (C) 1998-2015 Werner Koch
+ * Copyright (C) 1998-2016 Werner Koch
  * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
@@ -51,7 +51,8 @@
 
 static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
                        int verbose);
-static void show_names (estream_t fp, KBNODE keyblock, PKT_public_key * pk,
+static void show_names (ctrl_t ctrl, estream_t fp,
+                        kbnode_t keyblock, PKT_public_key * pk,
                        unsigned int flag, int with_prefs);
 static void show_key_with_all_names (ctrl_t ctrl, estream_t fp,
                                      KBNODE keyblock, int only_marked,
@@ -61,8 +62,8 @@ static void show_key_with_all_names (ctrl_t ctrl, estream_t fp,
 static void show_key_and_fingerprint (kbnode_t keyblock, int with_subkeys);
 static void show_key_and_grip (kbnode_t keyblock);
 static void subkey_expire_warning (kbnode_t keyblock);
-static int menu_adduid (KBNODE keyblock, int photo, const char *photo_name,
-                        const char *uidstr);
+static int menu_adduid (ctrl_t ctrl, kbnode_t keyblock,
+                        int photo, const char *photo_name, const char *uidstr);
 static void menu_deluid (KBNODE pub_keyblock);
 static int menu_delsig (KBNODE pub_keyblock);
 static int menu_clean (KBNODE keyblock, int self_only);
@@ -85,13 +86,13 @@ static int count_selected_uids (KBNODE keyblock);
 static int real_uids_left (KBNODE keyblock);
 static int count_selected_keys (KBNODE keyblock);
 static int menu_revsig (KBNODE keyblock);
-static int menu_revuid (KBNODE keyblock);
+static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock);
 static int menu_revkey (KBNODE pub_keyblock);
 static int menu_revsubkey (KBNODE pub_keyblock);
 #ifndef NO_TRUST_MODELS
 static int enable_disable_key (KBNODE keyblock, int disable);
 #endif /*!NO_TRUST_MODELS*/
-static void menu_showphoto (KBNODE keyblock);
+static void menu_showphoto (ctrl_t ctrl, kbnode_t keyblock);
 
 static int update_trust = 0;
 
@@ -350,8 +351,9 @@ sig_comparison (const void *av, const void *bv)
     return 1;
 
   ndataa = pubkey_get_nsig (a->pubkey_algo);
-  ndatab = pubkey_get_nsig (a->pubkey_algo);
-  log_assert (ndataa == ndatab);
+  ndatab = pubkey_get_nsig (b->pubkey_algo);
+  if (ndataa != ndatab)
+    return (ndataa < ndatab)? -1 : 1;
 
   for (i = 0; i < ndataa; i ++)
     {
@@ -570,7 +572,8 @@ check_all_keysigs (KBNODE kb, int only_selected, int only_selfsigs)
 
           sig = n->pkt->pkt.signature;
 
-          pending_desc = xasprintf ("  sig: class: 0x%x, issuer: %s, timestamp: %s (%lld), digest: %02x %02x",
+          pending_desc = xasprintf ("  sig: class: 0x%x, issuer: %s,"
+                                    " timestamp: %s (%lld), digest: %02x %02x",
                                     sig->sig_class,
                                     keystr (sig->keyid),
                                     isotimestamp (sig->timestamp),
@@ -596,8 +599,9 @@ check_all_keysigs (KBNODE kb, int only_selected, int only_selfsigs)
                     {
                       if (pending_desc)
                         log_debug ("%s", pending_desc);
-                      log_debug ("    Can't check signature allegedly issued by %s: %s\n",
-                                keystr (sig->keyid), gpg_strerror (err));
+                      log_debug ("    Can't check signature allegedly"
+                                 " issued by %s: %s\n",
+                                 keystr (sig->keyid), gpg_strerror (err));
                     }
                   missing_issuer ++;
                   break;
@@ -1688,7 +1692,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
           err = hexkeygrip_from_pk (pk, &hexgrip);
           if (err)
             goto leave;
-          err = agent_get_keyinfo (ctrl, hexgrip, &serialno);
+          err = agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
           if (!err && serialno)
             ; /* Key on card.  */
           else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
@@ -1726,7 +1730,8 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
             goto leave;
 
           desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_NORMAL, 1);
-          err = agent_passwd (ctrl, hexgrip, desc, &cache_nonce, &passwd_nonce);
+          err = agent_passwd (ctrl, hexgrip, desc, 0,
+                              &cache_nonce, &passwd_nonce);
           xfree (desc);
 
           if (err)
@@ -2021,7 +2026,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
      and run the stale check as early as possible.  Note, that for
      non- W32 platforms it is run indirectly trough a call to
      get_validity ().  */
-  check_trustdb_stale ();
+  check_trustdb_stale (ctrl);
 #endif
 
   /* Get the public key */
@@ -2206,8 +2211,9 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdCHECK:
-         check_all_keysigs (keyblock, count_selected_uids (keyblock),
-                             !strcmp (arg_string, "selfsig"));
+         if (check_all_keysigs (keyblock, count_selected_uids (keyblock),
+                                 !strcmp (arg_string, "selfsig")))
+            modified = 1;
          break;
 
        case cmdSIGN:
@@ -2293,7 +2299,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          photo = 1;
          /* fall through */
        case cmdADDUID:
-         if (menu_adduid (keyblock, photo, arg_string, NULL))
+         if (menu_adduid (ctrl, keyblock, photo, arg_string, NULL))
            {
              update_trust = 1;
              redisplay = 1;
@@ -2346,7 +2352,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdADDKEY:
-         if (!generate_subkeypair (ctrl, keyblock))
+         if (!generate_subkeypair (ctrl, keyblock, NULL, NULL, NULL))
            {
              redisplay = 1;
              modified = 1;
@@ -2422,7 +2428,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
             else if (*arg_string == '~')
               fname = make_filename (arg_string, NULL);
             else
-              fname = make_filename (opt.homedir, arg_string, NULL);
+              fname = make_filename (gnupg_homedir (), arg_string, NULL);
 
            /* Open that file.  */
            a = iobuf_open (fname);
@@ -2535,7 +2541,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                       n1 > 1 ? _("Really revoke all selected user IDs? (y/N) ")
                      :        _("Really revoke this user ID? (y/N) ")))
              {
-               if (menu_revuid (keyblock))
+               if (menu_revuid (ctrl, keyblock))
                  {
                    modified = 1;
                    redisplay = 1;
@@ -2629,7 +2635,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 
          show_key_with_all_names (ctrl, NULL, keyblock, 0, 0, 0, 1, 0, 0);
          tty_printf ("\n");
-         if (edit_ownertrust (find_kbnode (keyblock,
+         if (edit_ownertrust (ctrl, find_kbnode (keyblock,
                                            PKT_PUBLIC_KEY)->pkt->pkt.
                               public_key, 1))
            {
@@ -2646,7 +2652,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          {
            int count = count_selected_uids (keyblock);
            log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
-           show_names (NULL, keyblock, keyblock->pkt->pkt.public_key,
+           show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key,
                        count ? NODFLG_SELUID : 0, 1);
          }
          break;
@@ -2655,7 +2661,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          {
            int count = count_selected_uids (keyblock);
            log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
-           show_names (NULL, keyblock, keyblock->pkt->pkt.public_key,
+           show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key,
                        count ? NODFLG_SELUID : 0, 2);
          }
          break;
@@ -2731,7 +2737,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 #endif /*!NO_TRUST_MODELS*/
 
        case cmdSHOWPHOTO:
-         menu_showphoto (keyblock);
+         menu_showphoto (ctrl, keyblock);
          break;
 
        case cmdCLEAN:
@@ -2861,7 +2867,7 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 
 #ifdef HAVE_W32_SYSTEM
   /* See keyedit_menu for why we need this.  */
-  check_trustdb_stale ();
+  check_trustdb_stale (ctrl);
 #endif
 
   /* Search the key; we don't want the whole getkey stuff here.  */
@@ -2912,7 +2918,7 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 
   fix_keyblock (&keyblock);
 
-  if (menu_adduid (keyblock, 0, NULL, uidstring))
+  if (menu_adduid (ctrl, keyblock, 0, NULL, uidstring))
     {
       err = keydb_update_keyblock (kdbhd, keyblock);
       if (err)
@@ -2932,6 +2938,75 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 }
 
 
+/* Find a keyblock by fingerprint because only this uniquely
+ * identifies a key and may thus be used to select a key for
+ * unattended subkey creation os key signing.  */
+static gpg_error_t
+find_by_primary_fpr (ctrl_t ctrl, const char *fpr,
+                     kbnode_t *r_keyblock, KEYDB_HANDLE *r_kdbhd)
+{
+  gpg_error_t err;
+  kbnode_t keyblock = NULL;
+  KEYDB_HANDLE kdbhd = NULL;
+  KEYDB_SEARCH_DESC desc;
+  byte fprbin[MAX_FINGERPRINT_LEN];
+  size_t fprlen;
+
+  *r_keyblock = NULL;
+  *r_kdbhd = NULL;
+
+  if (classify_user_id (fpr, &desc, 1)
+      || !(desc.mode == KEYDB_SEARCH_MODE_FPR
+           || desc.mode == KEYDB_SEARCH_MODE_FPR16
+           || desc.mode == KEYDB_SEARCH_MODE_FPR20))
+    {
+      log_error (_("\"%s\" is not a fingerprint\n"), fpr);
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
+  err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
+  if (err)
+    {
+      log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Check that the primary fingerprint has been given. */
+  fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen);
+  if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16
+      && !memcmp (fprbin, desc.u.fpr, 16))
+    ;
+  else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR
+           && !memcmp (fprbin, desc.u.fpr, 16)
+           && !desc.u.fpr[16]
+           && !desc.u.fpr[17]
+           && !desc.u.fpr[18]
+           && !desc.u.fpr[19])
+    ;
+  else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20
+                            || desc.mode == KEYDB_SEARCH_MODE_FPR)
+           && !memcmp (fprbin, desc.u.fpr, 20))
+    ;
+  else
+    {
+      log_error (_("\"%s\" is not the primary fingerprint\n"), fpr);
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
+
+  *r_keyblock = keyblock;
+  keyblock = NULL;
+  *r_kdbhd = kdbhd;
+  kdbhd = NULL;
+  err = 0;
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+  return err;
+}
+
+
 /* Unattended key signing function.  If the key specifified by FPR is
    available and FPR is the primary fingerprint all user ids of the
    key are signed using the default signing key.  If UIDS is an empty
@@ -2946,7 +3021,6 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
   kbnode_t keyblock = NULL;
   KEYDB_HANDLE kdbhd = NULL;
   int modified = 0;
-  KEYDB_SEARCH_DESC desc;
   PKT_public_key *pk;
   kbnode_t node;
   strlist_t sl;
@@ -2954,53 +3028,14 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
 
 #ifdef HAVE_W32_SYSTEM
   /* See keyedit_menu for why we need this.  */
-  check_trustdb_stale ();
+  check_trustdb_stale (ctrl);
 #endif
 
   /* We require a fingerprint because only this uniquely identifies a
      key and may thus be used to select a key for unattended key
      signing.  */
-  if (classify_user_id (fpr, &desc, 1)
-      || !(desc.mode == KEYDB_SEARCH_MODE_FPR
-           || desc.mode == KEYDB_SEARCH_MODE_FPR16
-           || desc.mode == KEYDB_SEARCH_MODE_FPR20))
-    {
-      log_error (_("\"%s\" is not a fingerprint\n"), fpr);
-      goto leave;
-    }
-  err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
-  if (err)
-    {
-      log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
-      goto leave;
-    }
-
-  /* Check that the primary fingerprint has been given. */
-  {
-    byte fprbin[MAX_FINGERPRINT_LEN];
-    size_t fprlen;
-
-    fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen);
-    if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16
-        && !memcmp (fprbin, desc.u.fpr, 16))
-      ;
-    else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR
-             && !memcmp (fprbin, desc.u.fpr, 16)
-             && !desc.u.fpr[16]
-             && !desc.u.fpr[17]
-             && !desc.u.fpr[18]
-             && !desc.u.fpr[19])
-      ;
-    else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20
-                              || desc.mode == KEYDB_SEARCH_MODE_FPR)
-             && !memcmp (fprbin, desc.u.fpr, 20))
-      ;
-    else
-      {
-        log_error (_("\"%s\" is not the primary fingerprint\n"), fpr);
-        goto leave;
-      }
-  }
+  if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
+    goto leave;
 
   if (fix_keyblock (&keyblock))
     modified++;
@@ -3126,6 +3161,67 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
 }
 
 
+/* Unattended subkey creation function.
+ *
+ */
+void
+keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
+                      const char *usagestr, const char *expirestr)
+{
+  gpg_error_t err;
+  kbnode_t keyblock;
+  KEYDB_HANDLE kdbhd;
+  int modified = 0;
+  PKT_public_key *pk;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* We require a fingerprint because only this uniquely identifies a
+   * key and may thus be used to select a key for unattended subkey
+   * creation.  */
+  if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
+    goto leave;
+
+  if (fix_keyblock (&keyblock))
+    modified++;
+
+  pk = keyblock->pkt->pkt.public_key;
+  if (pk->flags.revoked)
+    {
+      if (!opt.verbose)
+        show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
+      log_error ("%s%s", _("Key is revoked."), "\n");
+      goto leave;
+    }
+
+  /* Create the subkey.  Noet that the called function already prints
+   * an error message. */
+  if (!generate_subkeypair (ctrl, keyblock, algostr, usagestr, expirestr))
+    modified = 1;
+  es_fflush (es_stdout);
+
+  /* Store.  */
+  if (modified)
+    {
+      err = keydb_update_keyblock (kdbhd, keyblock);
+      if (err)
+        {
+          log_error (_("update failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+    }
+  else
+    log_info (_("Key not changed so no update needed.\n"));
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
 \f
 static void
 tty_print_notations (int indent, PKT_signature * sig)
@@ -3369,7 +3465,7 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
            es_putc ('e', fp);
          else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks))
            {
-             int trust = get_validity_info (pk, NULL);
+             int trust = get_validity_info (ctrl, pk, NULL);
              if (trust == 'u')
                ulti_hack = 1;
              es_putc (trust, fp);
@@ -3428,7 +3524,7 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
              int uid_validity;
 
              if (primary && !ulti_hack)
-               uid_validity = get_validity_info (primary, uid);
+               uid_validity = get_validity_info (ctrl, primary, uid);
              else
                uid_validity = 'u';
              es_fprintf (fp, "%c::::::::", uid_validity);
@@ -3482,7 +3578,7 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
            {
 #ifdef USE_TOFU
              enum tofu_policy policy;
-             if (! tofu_get_policy (primary, uid, &policy)
+             if (! tofu_get_policy (ctrl, primary, uid, &policy)
                  && policy != TOFU_POLICY_NONE)
                es_fprintf (fp, "%s", tofu_policy_str (policy));
 #endif /*USE_TOFU*/
@@ -3495,8 +3591,8 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
 
 
 static void
-show_names (estream_t fp,
-            KBNODE keyblock, PKT_public_key * pk, unsigned int flag,
+show_names (ctrl_t ctrl, estream_t fp,
+            kbnode_t keyblock, PKT_public_key * pk, unsigned int flag,
            int with_prefs)
 {
   KBNODE node;
@@ -3511,7 +3607,7 @@ show_names (estream_t fp,
          if (!flag || (flag && (node->flag & flag)))
            {
              if (!(flag & NODFLG_MARK_A) && pk)
-               tty_fprintf (fp, "%s ", uid_trust_string_fixed (pk, uid));
+               tty_fprintf (fp, "%s ", uid_trust_string_fixed (ctrl, pk, uid));
 
              if (flag & NODFLG_MARK_A)
                tty_fprintf (fp, "     ");
@@ -3598,12 +3694,12 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
               * output */
              static int did_warn = 0;
 
-             trust = get_validity_string (pk, NULL);
+             trust = get_validity_string (ctrl, pk, NULL);
              otrust = get_ownertrust_string (pk);
 
              /* Show a warning once */
              if (!did_warn
-                 && (get_validity (pk, NULL, NULL, 0)
+                 && (get_validity (ctrl, pk, NULL, NULL, 0)
                      & TRUST_FLAG_PENDING_CHECK))
                {
                  did_warn = 1;
@@ -3670,7 +3766,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
                 have_seckey = 0;
               }
             else
-              have_seckey = !agent_get_keyinfo (ctrl, hexgrip, &serialno);
+              have_seckey = !agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
             xfree (hexgrip);
           }
 
@@ -3790,7 +3886,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
        }
     }
 
-  show_names (fp,
+  show_names (ctrl, fp,
               keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs);
 
   if (do_warn && !nowarn)
@@ -4035,8 +4131,8 @@ subkey_expire_warning (kbnode_t keyblock)
  * user id.
  */
 static int
-menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
-             const char *uidstring)
+menu_adduid (ctrl_t ctrl, kbnode_t pub_keyblock,
+             int photo, const char *photo_name, const char *uidstring)
 {
   PKT_user_id *uid;
   PKT_public_key *pk = NULL;
@@ -4098,7 +4194,7 @@ menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
            }
        }
 
-      uid = generate_photo_id (pk, photo_name);
+      uid = generate_photo_id (ctrl, pk, photo_name);
     }
   else
     uid = generate_user_id (pub_keyblock, uidstring);
@@ -6013,7 +6109,7 @@ reloop:                   /* (must use this, because we are modifing the list) */
 /* Revoke a user ID (i.e. revoke a user ID selfsig).  Return true if
    keyblock changed.  */
 static int
-menu_revuid (KBNODE pub_keyblock)
+menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
   KBNODE node;
@@ -6094,7 +6190,7 @@ menu_revuid (KBNODE pub_keyblock)
                /* If the trustdb has an entry for this key+uid then the
                   trustdb needs an update. */
                if (!update_trust
-                   && (get_validity (pk, uid, NULL, 0) & TRUST_MASK) >=
+                   && (get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK) >=
                    TRUST_UNDEFINED)
                  update_trust = 1;
 #endif /*!NO_TRUST_MODELS*/
@@ -6256,7 +6352,7 @@ enable_disable_key (KBNODE keyblock, int disable)
 
 
 static void
-menu_showphoto (KBNODE keyblock)
+menu_showphoto (ctrl_t ctrl, kbnode_t keyblock)
 {
   KBNODE node;
   int select_all = !count_selected_uids (keyblock);
@@ -6293,7 +6389,7 @@ menu_showphoto (KBNODE keyblock)
                                    "key %s (uid %d)\n"),
                                  image_type_to_string (type, 1),
                                  (ulong) size, keystr_from_pk (pk), count);
-                     show_photos (&uid->attribs[i], 1, pk, uid);
+                     show_photos (ctrl, &uid->attribs[i], 1, pk, uid);
                    }
                }
            }
index f9cbf21..74fd370 100644 (file)
@@ -1,6 +1,6 @@
 /* keygen.c - Generate a key pair
  * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
- * Copyright (C) 2014, 2015  Werner Koch
+ * Copyright (C) 2014, 2015, 2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
    is inside the bounds enforced by ask_keysize and gen_xxx.  */
 #define DEFAULT_STD_ALGO       PUBKEY_ALGO_RSA
 #define DEFAULT_STD_KEYSIZE    2048
+#define DEFAULT_STD_KEYUSE     (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)
 #define DEFAULT_STD_CURVE      NULL
 #define DEFAULT_STD_SUBALGO    PUBKEY_ALGO_RSA
 #define DEFAULT_STD_SUBKEYSIZE 2048
+#define DEFAULT_STD_SUBKEYUSE  PUBKEY_USAGE_ENC
 #define DEFAULT_STD_SUBCURVE   NULL
 
 /* Flag bits used during key generation.  */
@@ -134,6 +136,12 @@ static byte zip_prefs[MAX_PREFS];
 static int nzip_prefs;
 static int mdc_available,ks_modify;
 
+static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+                                     const char *algostr, const char *usagestr,
+                                     const char *expirestr,
+                                     int *r_algo, unsigned int *r_usage,
+                                     u32 *r_expire,
+                                     unsigned int *r_nbits, char **r_curve);
 static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                                 struct output_control_s *outctrl, int card );
 static int write_keyblock (iobuf_t out, kbnode_t node);
@@ -158,11 +166,14 @@ print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
   if (letter || pk)
     {
       *p++ = letter;
-      *p++ = ' ';
-      fingerprint_from_pk (pk, array, &n);
-      s = array;
-      for (i=0; i < n ; i++, s++, p += 2)
-        sprintf (p, "%02X", *s);
+      if (pk)
+        {
+          *p++ = ' ';
+          fingerprint_from_pk (pk, array, &n);
+          s = array;
+          for (i=0; i < n ; i++, s++, p += 2)
+            sprintf (p, "%02X", *s);
+        }
     }
   if (*handle)
     {
@@ -1296,14 +1307,15 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
 static int
 common_gen (const char *keyparms, int algo, const char *algoelem,
             kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
-            int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+            int keygen_flags, const char *passphrase,
+            char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   PACKET *pkt;
   PKT_public_key *pk;
   gcry_sexp_t s_key;
 
-  err = agent_genkey (NULL, cache_nonce_addr, keyparms,
+  err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms,
                       !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
                       passphrase,
                       &s_key);
@@ -1364,7 +1376,8 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
 static int
 gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   char *keyparms;
@@ -1405,7 +1418,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "pgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1419,7 +1433,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
 static gpg_error_t
 gen_dsa (unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   unsigned int qbits;
@@ -1492,7 +1507,8 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1507,7 +1523,8 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 static gpg_error_t
 gen_ecc (int algo, const char *curve, kbnode_t pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
   char *keyparms;
@@ -1549,7 +1566,8 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
     {
       err = common_gen (keyparms, algo, "",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1563,7 +1581,8 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
 static int
 gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   char *keyparms;
@@ -1604,7 +1623,8 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "ne",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -2017,88 +2037,47 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
 }
 
 
-/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
-   is not 0, the function asks for the size of the encryption
-   subkey. */
-static unsigned
-ask_keysize (int algo, unsigned int primary_keysize)
+static void
+get_keysize_range (int algo,
+                   unsigned int *min, unsigned int *def, unsigned int *max)
 {
-  unsigned int nbits;
-  unsigned int min = 1024;
-  unsigned int def = DEFAULT_STD_KEYSIZE;
-  unsigned int max = 4096;
-  int for_subkey = !!primary_keysize;
-  int autocomp = 0;
-
-  if (primary_keysize && !opt.expert)
-    {
-      /* Deduce the subkey size from the primary key size.  */
-      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
-        nbits = 3072; /* For performance reasons we don't support more
-                         than 3072 bit DSA.  However we won't see this
-                         case anyway because DSA can't be used as an
-                         encryption subkey ;-). */
-      else
-        nbits = primary_keysize;
-      autocomp = 1;
-      goto leave;
-    }
+  *min = 1024;
+  *def = DEFAULT_STD_KEYSIZE;
+  *max = 4096;
 
   /* Deviations from the standard values.  */
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
-      min = opt.expert? 768 : 1024;
-      def=2048;
-      max=3072;
+      *min = opt.expert? 768 : 1024;
+      *def=2048;
+      *max=3072;
       break;
 
     case PUBKEY_ALGO_ECDSA:
     case PUBKEY_ALGO_ECDH:
-      min=256;
-      def=256;
-      max=521;
+      *min=256;
+      *def=256;
+      *max=521;
       break;
 
     case PUBKEY_ALGO_EDDSA:
-      min=255;
-      def=255;
-      max=441;
+      *min=255;
+      *def=255;
+      *max=441;
       break;
     }
+}
 
-  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
-            openpgp_pk_algo_name (algo), min, max);
-
-  for (;;)
-    {
-      char *prompt, *answer;
-
-      if (for_subkey)
-        prompt = xasprintf (_("What keysize do you want "
-                              "for the subkey? (%u) "), def);
-      else
-        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
-      answer = cpr_get ("keygen.size", prompt);
-      cpr_kill_prompt ();
-      nbits = *answer? atoi (answer): def;
-      xfree(prompt);
-      xfree(answer);
-
-      if(nbits<min || nbits>max)
-       tty_printf(_("%s keysizes must be in the range %u-%u\n"),
-                  openpgp_pk_algo_name (algo), min, max);
-      else
-       break;
-    }
-
-  tty_printf (_("Requested keysize is %u bits\n"), nbits);
 
- leave:
+/* Return a fixed up keysize depending on ALGO.  */
+static unsigned int
+fixup_keysize (unsigned int nbits, int algo, int silent)
+{
   if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
     {
       nbits = ((nbits + 63) / 64) * 64;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits);
     }
   else if (algo == PUBKEY_ALGO_EDDSA)
@@ -2109,7 +2088,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 255;
           else
             nbits = 441;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
@@ -2123,14 +2102,14 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 384;
           else
             nbits = 521;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
   else if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits );
     }
 
@@ -2138,6 +2117,66 @@ ask_keysize (int algo, unsigned int primary_keysize)
 }
 
 
+/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
+   is not 0, the function asks for the size of the encryption
+   subkey. */
+static unsigned
+ask_keysize (int algo, unsigned int primary_keysize)
+{
+  unsigned int nbits;
+  unsigned int min, def, max;
+  int for_subkey = !!primary_keysize;
+  int autocomp = 0;
+
+  get_keysize_range (algo, &min, &def, &max);
+
+  if (primary_keysize && !opt.expert)
+    {
+      /* Deduce the subkey size from the primary key size.  */
+      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
+        nbits = 3072; /* For performance reasons we don't support more
+                         than 3072 bit DSA.  However we won't see this
+                         case anyway because DSA can't be used as an
+                         encryption subkey ;-). */
+      else
+        nbits = primary_keysize;
+      autocomp = 1;
+      goto leave;
+    }
+
+  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
+            openpgp_pk_algo_name (algo), min, max);
+
+  for (;;)
+    {
+      char *prompt, *answer;
+
+      if (for_subkey)
+        prompt = xasprintf (_("What keysize do you want "
+                              "for the subkey? (%u) "), def);
+      else
+        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
+      answer = cpr_get ("keygen.size", prompt);
+      cpr_kill_prompt ();
+      nbits = *answer? atoi (answer): def;
+      xfree(prompt);
+      xfree(answer);
+
+      if(nbits<min || nbits>max)
+       tty_printf(_("%s keysizes must be in the range %u-%u\n"),
+                  openpgp_pk_algo_name (algo), min, max);
+      else
+       break;
+    }
+
+  tty_printf (_("Requested keysize is %u bits\n"), nbits);
+
+ leave:
+  nbits = fixup_keysize (nbits, algo, autocomp);
+  return nbits;
+}
+
+
 /* Ask for the curve.  ALGO is the selected algorithm which this
    function may adjust.  Returns a malloced string with the name of
    the curve.  BOTH tells that gpg creates a primary and subkey. */
@@ -2724,7 +2763,8 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 static int
 do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
            u32 timestamp, u32 expiredate, int is_subkey,
-           int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+           int keygen_flags, const char *passphrase,
+           char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
 
@@ -2739,18 +2779,22 @@ do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
 
   if (algo == PUBKEY_ALGO_ELGAMAL_E)
     err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, passphrase, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_DSA)
     err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, passphrase, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA
            || algo == PUBKEY_ALGO_ECDH)
     err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, passphrase, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_RSA)
     err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, passphrase, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else
     BUG();
 
@@ -2885,6 +2929,52 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   return i;
 }
 
+
+/* Parse a usage string.  The usage keywords "auth", "sign", "encr"
+ * may be elimited by space, tab, or comma.  On error -1 is returned
+ * instead of the usage flags/  */
+static int
+parse_usagestr (const char *usagestr)
+{
+  gpg_error_t err;
+  char **tokens = NULL;
+  const char *s;
+  int i;
+  unsigned int use = 0;
+
+  tokens = strtokenize (usagestr, " \t,");
+  if (!tokens)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("strtokenize failed: %s\n", gpg_strerror (err));
+      return -1;
+    }
+
+  for (i=0; (s = tokens[i]); i++)
+    {
+      if (!*s)
+        ;
+      else if (!ascii_strcasecmp (s, "sign"))
+        use |= PUBKEY_USAGE_SIG;
+      else if (!ascii_strcasecmp (s, "encrypt")
+                || !ascii_strcasecmp (s, "encr"))
+        use |= PUBKEY_USAGE_ENC;
+      else if (!ascii_strcasecmp (s, "auth"))
+        use |= PUBKEY_USAGE_AUTH;
+      else if (!ascii_strcasecmp (s, "cert"))
+        use |= PUBKEY_USAGE_CERT;
+      else
+        {
+          xfree (tokens);
+          return -1; /* error */
+        }
+    }
+
+  xfree (tokens);
+  return use;
+}
+
+
 /*
  * Parse the usage parameter and set the keyflags.  Returns -1 on
  * error, 0 for no usage given or 1 for usage available.
@@ -2893,33 +2983,24 @@ static int
 parse_parameter_usage (const char *fname,
                        struct para_data_s *para, enum para_name key)
 {
-    struct para_data_s *r = get_parameter( para, key );
-    char *p, *pn;
-    unsigned int use;
-
-    if( !r )
-       return 0; /* none (this is an optional parameter)*/
-
-    use = 0;
-    pn = r->u.value;
-    while ( (p = strsep (&pn, " \t,")) ) {
-        if ( !*p)
-            ;
-        else if ( !ascii_strcasecmp (p, "sign") )
-            use |= PUBKEY_USAGE_SIG;
-        else if ( !ascii_strcasecmp (p, "encrypt") )
-            use |= PUBKEY_USAGE_ENC;
-        else if ( !ascii_strcasecmp (p, "auth") )
-            use |= PUBKEY_USAGE_AUTH;
-        else {
-            log_error("%s:%d: invalid usage list\n", fname, r->lnr );
-            return -1; /* error */
-        }
+  struct para_data_s *r = get_parameter( para, key );
+  int i;
+
+  if (!r)
+    return 0; /* none (this is an optional parameter)*/
+
+  i = parse_usagestr (r->u.value);
+  if (i == -1)
+    {
+      log_error ("%s:%d: invalid usage list\n", fname, r->lnr );
+      return -1; /* error */
     }
-    r->u.usage = use;
-    return 1;
+
+  r->u.usage = i;
+  return 1;
 }
 
+
 static int
 parse_revocation_key (const char *fname,
                      struct para_data_s *para, enum para_name key)
@@ -3409,13 +3490,20 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
 /* Helper for quick_generate_keypair.  */
 static struct para_data_s *
 quickgen_set_para (struct para_data_s *para, int for_subkey,
-                   int algo, int nbits, const char *curve)
+                   int algo, int nbits, const char *curve, unsigned int use)
 {
   struct para_data_s *r;
 
-  r = xmalloc_clear (sizeof *r + 20);
+  r = xmalloc_clear (sizeof *r + 30);
   r->key = for_subkey? pSUBKEYUSAGE :  pKEYUSAGE;
-  strcpy (r->u.value, for_subkey ? "encrypt" : "sign");
+  if (use)
+    snprintf (r->u.value, 30, "%s%s%s%s",
+              (use & PUBKEY_USAGE_ENC)?  "encr " : "",
+              (use & PUBKEY_USAGE_SIG)?  "sign " : "",
+              (use & PUBKEY_USAGE_AUTH)? "auth " : "",
+              (use & PUBKEY_USAGE_CERT)? "cert " : "");
+  else
+    strcpy (r->u.value, for_subkey ? "encr" : "sign");
   r->next = para;
   para = r;
   r = xmalloc_clear (sizeof *r + 20);
@@ -3449,7 +3537,8 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
  * Unattended generation of a standard key.
  */
 void
-quick_generate_keypair (ctrl_t ctrl, const char *uid)
+quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
+                        const char *usagestr, const char *expirestr)
 {
   gpg_error_t err;
   struct para_data_s *para = NULL;
@@ -3460,6 +3549,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
   memset (&outctrl, 0, sizeof outctrl);
 
   use_tty = (!opt.batch && !opt.answer_yes
+             && !*algostr && !*usagestr && !*expirestr
              && !cpr_enabled ()
              && gnupg_isatty (fileno (stdin))
              && gnupg_isatty (fileno (stdout))
@@ -3520,12 +3610,39 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
       }
   }
 
-  para = quickgen_set_para (para, 0,
-                            DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
-                            DEFAULT_STD_CURVE);
-  para = quickgen_set_para (para, 1,
-                            DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
-                            DEFAULT_STD_SUBCURVE);
+  if (*algostr || *usagestr || *expirestr)
+    {
+      /* Extended unattended mode.  Creates only the primary key. */
+      int algo;
+      unsigned int use;
+      u32 expire;
+      unsigned int nbits;
+      char *curve;
+
+      err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
+                                     &algo, &use, &expire, &nbits, &curve);
+      if (err)
+        {
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
+          goto leave;
+        }
+
+      para = quickgen_set_para (para, 0, algo, nbits, curve, use);
+      r = xmalloc_clear (sizeof *r + 20);
+      r->key = pKEYEXPIRE;
+      r->u.expire = expire;
+      r->next = para;
+      para = r;
+    }
+  else
+    {
+      para = quickgen_set_para (para, 0,
+                                DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
+                                DEFAULT_STD_CURVE, 0);
+      para = quickgen_set_para (para, 1,
+                                DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
+                                DEFAULT_STD_SUBCURVE, 0);
+    }
 
   /* If the pinentry loopback mode is not and we have a static
      passphrase (i.e. set with --passphrase{,-fd,-file} while in batch
@@ -3543,6 +3660,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
     }
 
   proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0);
+
  leave:
   release_parameter_list (para);
 }
@@ -3786,10 +3904,10 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
                    , "--full-gen-key" );
       para = quickgen_set_para (para, 0,
                                 DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
-                                DEFAULT_STD_CURVE);
+                                DEFAULT_STD_CURVE, 0);
       para = quickgen_set_para (para, 1,
                                 DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
-                                DEFAULT_STD_SUBCURVE);
+                                DEFAULT_STD_SUBCURVE, 0);
     }
 
 
@@ -3948,19 +4066,23 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
       goto leave;
     }
 
-  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0);
+  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
+                          GCRY_CIPHER_MODE_AESWRAP, 0);
   if (!err)
     err = gcry_cipher_setkey (cipherhd, kek, keklen);
   if (err)
     {
-      log_error ("error setting up an encryption context: %s\n", gpg_strerror (err));
+      log_error ("error setting up an encryption context: %s\n",
+                 gpg_strerror (err));
       goto leave;
     }
 
-  err = receive_seckey_from_agent (ctrl, cipherhd, &cache_nonce, hexgrip, sk);
+  err = receive_seckey_from_agent (ctrl, cipherhd, 0,
+                                   &cache_nonce, hexgrip, sk);
   if (err)
     {
-      log_error ("error getting secret key from agent: %s\n", gpg_strerror (err));
+      log_error ("error getting secret key from agent: %s\n",
+                 gpg_strerror (err));
       goto leave;
     }
 
@@ -4068,7 +4190,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                      get_parameter_u32( para, pKEYEXPIRE ), 0,
                      outctrl->keygen_flags,
                      get_parameter_passphrase (para),
-                     &cache_nonce);
+                     &cache_nonce, NULL);
   else
     err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
                         &timestamp,
@@ -4131,7 +4253,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
                            s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags,
                            get_parameter_passphrase (para),
-                           &cache_nonce);
+                           &cache_nonce, NULL);
           /* Get the pointer to the generated public subkey packet.  */
           if (!err)
             {
@@ -4143,7 +4265,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
               log_assert (sub_psk);
 
               if (s)
-                err = card_store_key_with_backup (ctrl, sub_psk, opt.homedir);
+                err = card_store_key_with_backup (ctrl,
+                                                  sub_psk, gnupg_homedir ());
             }
         }
       else
@@ -4260,12 +4383,144 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
 }
 
 
+static gpg_error_t
+parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+                         const char *algostr, const char *usagestr,
+                         const char *expirestr,
+                         int *r_algo, unsigned int *r_usage, u32 *r_expire,
+                         unsigned int *r_nbits, char **r_curve)
+{
+  int algo;
+  unsigned int use, nbits;
+  u32 expire;
+  int wantuse;
+  unsigned int min, def, max;
+  const char *curve = NULL;
+  int eccalgo = 0;
+
+  *r_curve = NULL;
+
+  nbits = 0;
+  /* Parse the algo string.  */
+  if (!algostr || !*algostr
+      || !strcmp (algostr, "default") || !strcmp (algostr, "-"))
+    {
+      algo = for_subkey? DEFAULT_STD_SUBALGO : DEFAULT_STD_ALGO;
+      use = for_subkey?  DEFAULT_STD_SUBKEYUSE : DEFAULT_STD_KEYUSE;
+      nbits = for_subkey?DEFAULT_STD_SUBKEYSIZE : DEFAULT_STD_KEYSIZE;
+    }
+  else if (*algostr == '&' && strlen (algostr) == 41)
+    {
+      /* Take algo from existing key.  */
+      algo = check_keygrip (ctrl, algostr+1);
+      /* FIXME: We need the curve name as well.  */
+      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+    }
+  else if (!strncmp (algostr, "rsa", 3))
+    {
+      algo = PUBKEY_ALGO_RSA;
+      use = for_subkey? DEFAULT_STD_SUBKEYUSE : DEFAULT_STD_KEYUSE;
+      if (algostr[3])
+        nbits = atoi (algostr + 3);
+    }
+  else if (!strncmp (algostr, "elg", 3))
+    {
+      algo = PUBKEY_ALGO_ELGAMAL_E;
+      use = PUBKEY_USAGE_ENC;
+      if (algostr[3])
+        nbits = atoi (algostr + 3);
+    }
+  else if (!strncmp (algostr, "dsa", 3))
+    {
+      algo = PUBKEY_ALGO_DSA;
+      use = PUBKEY_USAGE_SIG;
+      if (algostr[3])
+        nbits = atoi (algostr + 3);
+    }
+  else if ((curve = openpgp_is_curve_supported (algostr, &algo)))
+    {
+      if (!algo)
+        {
+          algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm.  */
+          eccalgo = 1;  /* Remember - we may need to fix it up.  */
+        }
+
+      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA)
+        use = PUBKEY_USAGE_SIG;
+      else
+        use = PUBKEY_USAGE_ENC;
+    }
+  else
+    return gpg_error (GPG_ERR_INV_CURVE);
+
+  /* Parse the usage string.  */
+  if (!usagestr || !*usagestr
+      || !strcmp (usagestr, "default") || !strcmp (usagestr, "-"))
+    ; /* Keep default usage */
+  else if ((wantuse = parse_usagestr (usagestr)) != -1)
+    {
+      use = wantuse;
+      if (eccalgo && !(use & PUBKEY_USAGE_ENC))
+        algo = PUBKEY_ALGO_ECDSA; /* Switch from ECDH to ECDSA.  */
+    }
+  else
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* Make sure a primary key has the CERT usage.  */
+  if (!for_subkey)
+    use |= PUBKEY_USAGE_CERT;
+
+  /* Check that usage is possible.  */
+  if (/**/((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
+           && !pubkey_get_nsig (algo))
+       || ((use & PUBKEY_USAGE_ENC)
+           && !pubkey_get_nenc (algo))
+       || (for_subkey && (use & PUBKEY_USAGE_CERT)))
+    return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+
+  /* Parse the expire string.  */
+  if (!expirestr || !*expirestr || !strcmp (expirestr, "none")
+      || !strcmp (expirestr, "never") || !strcmp (expirestr, "-"))
+    expire = 0;
+  else
+    expire = parse_expire_string (expirestr);
+  if (expire == (u32)-1 )
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* Make sure the keysize is in the allowed range.  */
+  get_keysize_range (algo, &min, &def, &max);
+  if (!nbits)
+    nbits = def;
+  else if (nbits < min)
+    nbits = min;
+  else if (nbits > max)
+    nbits = max;
+
+  nbits = fixup_keysize (nbits, algo, 1);
+
+  if (curve)
+    {
+      *r_curve = xtrystrdup (curve);
+      if (!*r_curve)
+        return gpg_error_from_syserror ();
+    }
+  *r_algo = algo;
+  *r_usage = use;
+  *r_expire = expire;
+  *r_nbits = nbits;
+  return 0;
+}
+
+
 /* Add a new subkey to an existing key.  Returns 0 if a new key has
-   been generated and put into the keyblocks.  */
+   been generated and put into the keyblocks.  If any of ALGOSTR,
+   USAGESTR, or EXPIRESTR is NULL interactive mode is used. */
 gpg_error_t
-generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
+generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
+                     const char *usagestr, const char *expirestr)
 {
   gpg_error_t err = 0;
+  int interactive;
   kbnode_t node;
   PKT_public_key *pri_psk = NULL;
   PKT_public_key *sub_psk = NULL;
@@ -4275,8 +4530,13 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   unsigned int nbits = 0;
   char *curve = NULL;
   u32 cur_time;
+  char *key_from_hexgrip = NULL;
   char *hexgrip = NULL;
   char *serialno = NULL;
+  char *cache_nonce = NULL;
+  char *passwd_nonce = NULL;
+
+  interactive = (!algostr || !usagestr || !expirestr);
 
   /* Break out the primary key.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@@ -4315,42 +4575,87 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   err = hexkeygrip_from_pk (pri_psk, &hexgrip);
   if (err)
     goto leave;
-  if (agent_get_keyinfo (NULL, hexgrip, &serialno))
+  if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
     {
-      tty_printf (_("Secret parts of primary key are not available.\n"));
+      if (interactive)
+        tty_printf (_("Secret parts of primary key are not available.\n"));
+      else
+        log_info (  _("Secret parts of primary key are not available.\n"));
+      err = gpg_error (GPG_ERR_NO_SECKEY);
       goto leave;
     }
   if (serialno)
-    tty_printf (_("Secret parts of primary key are stored on-card.\n"));
-
-  xfree (hexgrip);
-  hexgrip = NULL;
-  algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
-  log_assert (algo);
+    {
+      if (interactive)
+        tty_printf (_("Secret parts of primary key are stored on-card.\n"));
+      else
+        log_info (  _("Secret parts of primary key are stored on-card.\n"));
+    }
 
-  if (hexgrip)
-    nbits = 0;
-  else if (algo == PUBKEY_ALGO_ECDSA
-           || algo == PUBKEY_ALGO_EDDSA
-           || algo == PUBKEY_ALGO_ECDH)
-    curve = ask_curve (&algo, NULL);
-  else
-    nbits = ask_keysize (algo, 0);
+  if (interactive)
+    {
+      algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip);
+      log_assert (algo);
+
+      if (key_from_hexgrip)
+        nbits = 0;
+      else if (algo == PUBKEY_ALGO_ECDSA
+               || algo == PUBKEY_ALGO_EDDSA
+               || algo == PUBKEY_ALGO_ECDH)
+        curve = ask_curve (&algo, NULL);
+      else
+        nbits = ask_keysize (algo, 0);
 
-  expire = ask_expire_interval (0, NULL);
-  if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
-                                               _("Really create? (y/N) ")))
+      expire = ask_expire_interval (0, NULL);
+      if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
+                                                   _("Really create? (y/N) ")))
+        {
+          err = gpg_error (GPG_ERR_CANCELED);
+          goto leave;
+        }
+    }
+  else /* Unattended mode.  */
     {
-      err = gpg_error (GPG_ERR_CANCELED);
-      goto leave;
+      err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
+                                     &algo, &use, &expire, &nbits, &curve);
+      if (err)
+        goto leave;
     }
 
-  if (hexgrip)
-    err = do_create_from_keygrip (ctrl, algo, hexgrip,
-                                  keyblock, cur_time, expire, 1);
+  /* Verify the passphrase now so that we get a cache item for the
+   * primary key passphrase.  The agent also returns a passphrase
+   * nonce, which we can use to set the passphrase for the subkey to
+   * that of the primary key.  */
+  {
+    char *desc = gpg_format_keydesc (pri_psk, FORMAT_KEYDESC_NORMAL, 1);
+    err = agent_passwd (ctrl, hexgrip, desc, 1 /*=verify*/,
+                        &cache_nonce, &passwd_nonce);
+    xfree (desc);
+  }
+
+  /* Start creation.  */
+  if (key_from_hexgrip)
+    {
+      err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
+                                    keyblock, cur_time, expire, 1);
+    }
   else
-    err = do_create (algo, nbits, curve,
-                     keyblock, cur_time, expire, 1, 0, NULL, NULL);
+    {
+      const char *passwd;
+
+      /* If the pinentry loopback mode is not and we have a static
+         passphrase (i.e. set with --passphrase{,-fd,-file} while in batch
+         mode), we use that passphrase for the new subkey.  */
+      if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK
+          && have_static_passphrase ())
+        passwd = get_static_passphrase ();
+      else
+        passwd = NULL;
+
+      err = do_create (algo, nbits, curve,
+                       keyblock, cur_time, expire, 1, 0,
+                       passwd, &cache_nonce, &passwd_nonce);
+    }
   if (err)
     goto leave;
 
@@ -4360,16 +4665,21 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
       sub_psk = node->pkt->pkt.public_key;
 
   /* Write the binding signature.  */
-  err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time, NULL);
+  err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time,
+                          cache_nonce);
   if (err)
     goto leave;
 
-  write_status_text (STATUS_KEY_CREATED, "S");
+  print_status_key_created ('S', sub_psk, NULL);
+
 
  leave:
+  xfree (key_from_hexgrip);
   xfree (curve);
   xfree (hexgrip);
   xfree (serialno);
+  xfree (cache_nonce);
+  xfree (passwd_nonce);
   if (err)
     log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   return err;
@@ -4390,6 +4700,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   u32 expire;
   u32 cur_time;
   struct para_data_s *para = NULL;
+  PKT_public_key *sub_pk = NULL;
 
   log_assert (keyno >= 1 && keyno <= 3);
 
@@ -4456,8 +4767,6 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   /* Get the pointer to the generated public subkey packet.  */
   if (!err)
     {
-      PKT_public_key *sub_pk = NULL;
-
       for (node = pub_keyblock; node; node = node->next)
         if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
           sub_pk = node->pkt->pkt.public_key;
@@ -4470,7 +4779,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   if (err)
     log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   else
-    write_status_text (STATUS_KEY_CREATED, "S");
+    print_status_key_created ('S', sub_pk, NULL);
   release_parameter_list (para);
   return err;
 }
index bd808d2..e67f67f 100644 (file)
@@ -333,10 +333,15 @@ format_keyid (u32 *keyid, int format, char *buffer, int len)
   if (format == KF_DEFAULT)
     format = opt.keyid_format;
   if (format == KF_DEFAULT)
-    format = KF_SHORT;
+    format = KF_NONE;
 
   switch (format)
     {
+    case KF_NONE:
+      if (len)
+        *buffer = 0;
+      break;
+
     case KF_SHORT:
       snprintf (buffer, len, "%08lX", (ulong)keyid[1]);
       break;
@@ -375,10 +380,13 @@ keystrlen(void)
 {
   int format = opt.keyid_format;
   if (format == KF_DEFAULT)
-    format = KF_SHORT;
+    format = KF_NONE;
 
   switch(format)
     {
+    case KF_NONE:
+      return 0;
+
     case KF_SHORT:
       return 8;
 
@@ -401,22 +409,32 @@ const char *
 keystr (u32 *keyid)
 {
   static char keyid_str[KEYID_STR_SIZE];
-  return format_keyid (keyid, opt.keyid_format, keyid_str, sizeof (keyid_str));
-}
+  int format = opt.keyid_format;
 
+  if (format == KF_NONE)
+    format = KF_LONG;
 
+  return format_keyid (keyid, format, keyid_str, sizeof (keyid_str));
+}
+
+/* This function returns the key id of the main and possible the
+ * subkey as one string.  It is used by error messages.  */
 const char *
 keystr_with_sub (u32 *main_kid, u32 *sub_kid)
 {
   static char buffer[KEYID_STR_SIZE+1+KEYID_STR_SIZE];
   char *p;
+  int format = opt.keyid_format;
+
+  if (format == KF_NONE)
+    format = KF_LONG;
 
-  mem2str (buffer, keystr (main_kid), KEYID_STR_SIZE);
+  format_keyid (main_kid, format, buffer, KEYID_STR_SIZE);
   if (sub_kid)
     {
       p = buffer + strlen (buffer);
       *p++ = '/';
-      mem2str (p, keystr (sub_kid), KEYID_STR_SIZE);
+      format_keyid (sub_kid, format, p, KEYID_STR_SIZE);
     }
   return buffer;
 }
index 1649991..0ac763d 100644 (file)
@@ -130,7 +130,7 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
      is very bad for W32 because of a sharing violation. For real OSes
      it might lead to false results if we are later listing a keyring
      which is associated with the inode of a deleted file.  */
-  check_trustdb_stale ();
+  check_trustdb_stale (ctrl);
 
 #ifdef USE_TOFU
   tofu_begin_batch_update ();
@@ -154,7 +154,7 @@ secret_key_list (ctrl_t ctrl, strlist_t list)
 {
   (void)ctrl;
 
-  check_trustdb_stale ();
+  check_trustdb_stale (ctrl);
 
   if (!list)
     list_all (ctrl, 1, 0);
@@ -247,7 +247,7 @@ print_card_key_info (estream_t fp, kbnode_t keyblock)
               log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
               s2k_char = '?';
             }
-          else if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
+          else if (!agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
             s2k_char = serialno? '>':' ';
           else
             s2k_char = '#';  /* Key not found.  */
@@ -401,7 +401,7 @@ void
 show_notation (PKT_signature * sig, int indent, int mode, int which)
 {
   estream_t fp = mode ? log_get_stream () : es_stdout;
-  struct notation *nd, *notations;
+  notation_t nd, notations;
 
   if (which == 0)
     which = 3;
@@ -448,6 +448,10 @@ show_notation (PKT_signature * sig, int indent, int mode, int which)
        {
          write_status_buffer (STATUS_NOTATION_NAME,
                               nd->name, strlen (nd->name), 0);
+          if (nd->flags.critical || nd->flags.human)
+            write_status_text (STATUS_NOTATION_FLAGS,
+                               nd->flags.critical && nd->flags.human? "1 1" :
+                               nd->flags.critical? "1 0" : "0 1");
          write_status_buffer (STATUS_NOTATION_DATA,
                               nd->value, strlen (nd->value), 50);
        }
@@ -1010,7 +1014,7 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
 
 
 static void
-list_keyblock_print (KBNODE keyblock, int secret, int fpr,
+list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
                      struct keylist_context *listctx)
 {
   int rc;
@@ -1018,10 +1022,8 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
   KBNODE node;
   PKT_public_key *pk;
   int skip_sigs = 0;
-  int s2k_char;
   char *hexgrip = NULL;
   char *serialno = NULL;
-  char pkstrbuf[PUBKEY_STRING_SIZE];
 
   /* Get the keyid from the keyblock.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@@ -1043,62 +1045,19 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
 
   if (secret)
     {
-      if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
-        s2k_char = serialno? '>':' ';
+      /* Encode some info about the secret key in SECRET.  */
+      if (!agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
+        secret = serialno? 3 : 1;
       else
-        s2k_char = '#';  /* Key not found.  */
+        secret = 2;  /* Key not found.  */
     }
-  else
-    s2k_char = ' ';
 
-  check_trustdb_stale ();
-
-
-  es_fprintf (es_stdout, "%s%c  %s/%s %s",
-              secret? "sec":"pub",
-              s2k_char,
-              pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
-              keystr_from_pk (pk), datestr_from_pk (pk));
+  check_trustdb_stale (ctrl);
 
-  if ((opt.list_options & LIST_SHOW_USAGE))
-    {
-      es_fprintf (es_stdout, " [%s]", usagestr_from_pk (pk, 0));
-    }
-  if (pk->flags.revoked)
-    {
-      es_fprintf (es_stdout, " [");
-      es_fprintf (es_stdout, _("revoked: %s"), revokestr_from_pk (pk));
-      es_fprintf (es_stdout, "]");
-    }
-  else if (pk->has_expired)
-    {
-      es_fprintf (es_stdout, " [");
-      es_fprintf (es_stdout, _("expired: %s"), expirestr_from_pk (pk));
-      es_fprintf (es_stdout, "]");
-    }
-  else if (pk->expiredate)
-    {
-      es_fprintf (es_stdout, " [");
-      es_fprintf (es_stdout, _("expires: %s"), expirestr_from_pk (pk));
-      es_fprintf (es_stdout, "]");
-    }
+  /* Print the "pub" line and in KF_NONE mode the fingerprint.  */
+  print_key_line (es_stdout, pk, secret);
 
-#if 0
-  /* I need to think about this some more.  It's easy enough to
-     include, but it looks sort of confusing in the listing... */
-  if (opt.list_options & LIST_SHOW_VALIDITY)
-    {
-      int validity = get_validity (pk, NULL, NULL, 0);
-      es_fprintf (es_stdout, " [%s]", trust_value_to_string (validity));
-    }
-#endif
-
-  if (pk->pubkey_algo >= 100)
-    es_fprintf (es_stdout, " [experimental algorithm %d]", pk->pubkey_algo);
-
-  es_fprintf (es_stdout, "\n");
-
-  if (fpr)
+  if (fpr && opt.keyid_format != KF_NONE)
     print_fingerprint (NULL, pk, 0);
 
   if (opt.with_keygrip && hexgrip)
@@ -1116,6 +1075,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
        {
          PKT_user_id *uid = node->pkt->pkt.user_id;
           int indent;
+          int kl = opt.keyid_format == KF_NONE? 10 : keystrlen ();
 
          if ((uid->is_expired || uid->is_revoked)
              && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
@@ -1134,9 +1094,9 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
            {
              const char *validity;
 
-             validity = uid_trust_string_fixed (pk, uid);
-             indent = ((keystrlen () + (opt.legacy_list_mode? 9:11))
-                        - atoi (uid_trust_string_fixed (NULL, NULL)));
+             validity = uid_trust_string_fixed (ctrl, pk, uid);
+             indent = ((kl + (opt.legacy_list_mode? 9:11))
+                        - atoi (uid_trust_string_fixed (ctrl, NULL, NULL)));
              if (indent < 0 || indent > 40)
                indent = 0;
 
@@ -1144,7 +1104,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
            }
          else
             {
-              indent = keystrlen () + (opt.legacy_list_mode? 10:12);
+              indent = kl + (opt.legacy_list_mode? 10:12);
               es_fprintf (es_stdout, "uid%*s", indent, "");
             }
 
@@ -1174,7 +1134,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
             }
 
          if ((opt.list_options & LIST_SHOW_PHOTOS) && uid->attribs != NULL)
-           show_photos (uid->attribs, uid->numattribs, pk, uid);
+           show_photos (ctrl, uid->attribs, uid->numattribs, pk, uid);
        }
       else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
        {
@@ -1200,44 +1160,15 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
             }
           if (secret)
             {
-              if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
-                s2k_char = serialno? '>':' ';
+              if (!agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
+                secret = serialno? 3 : 1;
               else
-                s2k_char = '#';  /* Key not found.  */
+                secret = '2';  /* Key not found.  */
             }
-          else
-            s2k_char = ' ';
 
-         es_fprintf (es_stdout, "%s%c  %s/%s %s",
-                  secret? "ssb":"sub",
-                  s2k_char,
-                  pubkey_string (pk2, pkstrbuf, sizeof pkstrbuf),
-                 keystr_from_pk (pk2), datestr_from_pk (pk2));
-
-          if ((opt.list_options & LIST_SHOW_USAGE))
-            {
-              es_fprintf (es_stdout, " [%s]", usagestr_from_pk (pk2, 0));
-            }
-         if (pk2->flags.revoked)
-           {
-             es_fprintf (es_stdout, " [");
-             es_fprintf (es_stdout, _("revoked: %s"), revokestr_from_pk (pk2));
-             es_fprintf (es_stdout, "]");
-           }
-         else if (pk2->has_expired)
-           {
-             es_fprintf (es_stdout, " [");
-             es_fprintf (es_stdout, _("expired: %s"), expirestr_from_pk (pk2));
-             es_fprintf (es_stdout, "]");
-           }
-         else if (pk2->expiredate)
-           {
-             es_fprintf (es_stdout, " [");
-             es_fprintf (es_stdout, _("expires: %s"), expirestr_from_pk (pk2));
-             es_fprintf (es_stdout, "]");
-           }
-         es_putc ('\n', es_stdout);
-         if (fpr > 1)
+          /* Print the "sub" line.  */
+          print_key_line (es_stdout, pk2, secret);
+         if (fpr > 1 || opt.with_subkey_fingerprint)
             {
               print_fingerprint (NULL, pk2, 0);
               if (serialno)
@@ -1390,7 +1321,8 @@ print_revokers (estream_t fp, PKT_public_key * pk)
    record (i.e. requested via --list-secret-key).  If HAS_SECRET a
    secret key is available even if SECRET is not set.  */
 static void
-list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
+list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
+                     int secret, int has_secret, int fpr)
 {
   int rc;
   KBNODE kbctx;
@@ -1422,7 +1354,8 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
         log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
     }
   stubkey = 0;
-  if ((secret||has_secret) && agent_get_keyinfo (NULL, hexgrip, &serialno))
+  if ((secret || has_secret)
+      && agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
     stubkey = 1;  /* Key not found.  */
 
   keyid_from_pk (pk, keyid);
@@ -1437,7 +1370,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
     ;
   else
     {
-      trustletter = get_validity_info (pk, NULL);
+      trustletter = get_validity_info (ctrl, pk, NULL);
       if (trustletter == 'u')
         ulti_hack = 1;
       es_putc (trustletter, es_stdout);
@@ -1519,7 +1452,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
              int uid_validity;
 
              if (!ulti_hack)
-               uid_validity = get_validity_info (pk, uid);
+               uid_validity = get_validity_info (ctrl, pk, uid);
              else
                uid_validity = 'u';
              es_fprintf (es_stdout, "%s:%c::::", str, uid_validity);
@@ -1544,7 +1477,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
            {
 #ifdef USE_TOFU
              enum tofu_policy policy;
-             if (! tofu_get_policy (pk, uid, &policy)
+             if (! tofu_get_policy (ctrl, pk, uid, &policy)
                  && policy != TOFU_POLICY_NONE)
                es_fprintf (es_stdout, "%s", tofu_policy_str (policy));
 #endif /*USE_TOFU*/
@@ -1569,7 +1502,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
             }
           stubkey = 0;
           if ((secret||has_secret)
-              && agent_get_keyinfo (NULL, hexgrip, &serialno))
+              && agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
             stubkey = 1;  /* Key not found.  */
 
          keyid_from_pk (pk2, keyid2);
@@ -1609,11 +1542,11 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
             }
           es_putc (':', es_stdout);    /* End of field 15. */
           es_putc (':', es_stdout);    /* End of field 16. */
-          if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
-              || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
-              || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
+          if (pk2->pubkey_algo == PUBKEY_ALGO_ECDSA
+              || pk2->pubkey_algo == PUBKEY_ALGO_EDDSA
+              || pk2->pubkey_algo == PUBKEY_ALGO_ECDH)
             {
-              char *curve = openpgp_oid_to_str (pk->pkey[0]);
+              char *curve = openpgp_oid_to_str (pk2->pkey[0]);
               const char *name = openpgp_oid_to_curve (curve, 0);
               if (!name)
                 name = curve;
@@ -1814,9 +1747,9 @@ list_keyblock (ctrl_t ctrl,
   if (opt.print_pka_records || opt.print_dane_records)
     list_keyblock_pka (ctrl, keyblock);
   else if (opt.with_colons)
-    list_keyblock_colon (keyblock, secret, has_secret, fpr);
+    list_keyblock_colon (ctrl, keyblock, secret, has_secret, fpr);
   else
-    list_keyblock_print (keyblock, secret, fpr, listctx);
+    list_keyblock_print (ctrl, keyblock, secret, fpr, listctx);
   if (secret)
     es_fflush (es_stdout);
 }
@@ -1856,6 +1789,7 @@ print_icao_hexdigit (estream_t fp, int c)
  *      3: direct use of tty but only primary key.
  *      4: direct use of tty but only subkey.
  *     10: Same as 0 but with_colons etc is ignored.
+ *     20: Same as 0 but using a compact format.
  *
  * Modes 1 and 2 will try and print both subkey and primary key
  * fingerprints.  A MODE with bit 7 set is used internally.  If
@@ -1873,6 +1807,7 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
   int primary = 0;
   int with_colons = opt.with_colons;
   int with_icao   = opt.with_icao_spelling;
+  int compact = 0;
 
   if (mode == 10)
     {
@@ -1880,6 +1815,16 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
       with_colons = 0;
       with_icao = 0;
     }
+  else if (mode == 20)
+    {
+      mode = 0;
+      with_colons = 0;
+      compact = 1;
+    }
+
+  if (!opt.fingerprint && !opt.with_fingerprint
+      && opt.with_subkey_fingerprint && opt.keyid_format == KF_NONE)
+    compact = 1;
 
   if (pk->main_keyid[0] == pk->keyid[0]
       && pk->main_keyid[1] == pk->keyid[1])
@@ -1933,7 +1878,13 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
   else
     {
       fp = override_fp? override_fp : es_stdout;
-      text = _("      Key fingerprint =");
+      if (opt.keyid_format == KF_NONE)
+        {
+          text = "     ";  /* To indent ICAO spelling.  */
+          compact = 1;
+        }
+      else
+        text = _("      Key fingerprint =");
     }
 
   hexfingerprint (pk, hexfpr, sizeof hexfpr);
@@ -1941,11 +1892,18 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
     {
       es_fprintf (fp, "fpr:::::::::%s:", hexfpr);
     }
+  else if (compact && !opt.fingerprint && !opt.with_fingerprint)
+    {
+      tty_fprintf (fp, "%*s%s", 6, "", hexfpr);
+    }
   else
     {
       char fmtfpr[MAX_FORMATTED_FINGERPRINT_LEN + 1];
       format_hexfingerprint (hexfpr, fmtfpr, sizeof fmtfpr);
-      tty_fprintf (fp, "%s %s", text, fmtfpr);
+      if (compact)
+        tty_fprintf (fp, "%*s%s", 6, "", fmtfpr);
+      else
+        tty_fprintf (fp, "%s %s", text, fmtfpr);
     }
   tty_fprintf (fp, "\n");
   if (!with_colons && with_icao)
@@ -1992,6 +1950,75 @@ print_card_serialno (const char *serialno)
 }
 
 
+/* Print a public or secret (sub)key line.  Example:
+ *
+ * pub   dsa2048 2007-12-31 [SC] [expires: 2018-12-31]
+ *       80615870F5BAD690333686D0F2AD85AC1E42B367
+ *
+ * Some global options may result in a different output format.  If
+ * SECRET is set, "sec" or "ssb" is used instead of "pub" or "sub" and
+ * depending on the value a flag character is shown:
+ *
+ *    1 := ' ' Regular secret key
+ *    2 := '#' Stub secret key
+ *    3 := '>' Secret key is on a token.
+ */
+void
+print_key_line (estream_t fp, PKT_public_key *pk, int secret)
+{
+  char pkstrbuf[PUBKEY_STRING_SIZE];
+
+  tty_fprintf (fp, "%s%c  %s",
+               pk->flags.primary? (secret? "sec":"pub")
+               /**/             : (secret? "ssb":"sub"),
+               secret == 2? '#' : secret == 3? '>' : ' ',
+               pubkey_string (pk, pkstrbuf, sizeof pkstrbuf));
+  if (opt.keyid_format != KF_NONE)
+    tty_fprintf (fp, "/%s", keystr_from_pk (pk));
+  tty_fprintf (fp, " %s", datestr_from_pk (pk));
+
+  if ((opt.list_options & LIST_SHOW_USAGE))
+    {
+      tty_fprintf (fp, " [%s]", usagestr_from_pk (pk, 0));
+    }
+  if (pk->flags.revoked)
+    {
+      tty_fprintf (fp, " [");
+      tty_fprintf (fp, _("revoked: %s"), revokestr_from_pk (pk));
+      tty_fprintf (fp, "]");
+    }
+  else if (pk->has_expired)
+    {
+      tty_fprintf (fp, " [");
+      tty_fprintf (fp, _("expired: %s"), expirestr_from_pk (pk));
+      tty_fprintf (fp, "]");
+    }
+  else if (pk->expiredate)
+    {
+      tty_fprintf (fp, " [");
+      tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk));
+      tty_fprintf (fp, "]");
+    }
+
+#if 0
+  /* I need to think about this some more.  It's easy enough to
+     include, but it looks sort of confusing in the listing... */
+  if (opt.list_options & LIST_SHOW_VALIDITY)
+    {
+      int validity = get_validity (ctrl, pk, NULL, NULL, 0);
+      tty_fprintf (fp, " [%s]", trust_value_to_string (validity));
+    }
+#endif
+
+  if (pk->pubkey_algo >= 100)
+    tty_fprintf (fp, " [experimental algorithm %d]", pk->pubkey_algo);
+
+  tty_fprintf (fp, "\n");
+
+  if (pk->flags.primary && opt.keyid_format == KF_NONE)
+    print_fingerprint (fp, pk, 20);
+}
+
 
 void
 set_attrib_fd (int fd)
index 3486abb..d7105de 100644 (file)
@@ -1464,7 +1464,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
   /* If the original options didn't have fast import, and the trustdb
      is dirty, rebuild. */
   if(!(opt.keyserver_options.import_options&IMPORT_FAST))
-    check_or_update_trustdb ();
+    check_or_update_trustdb (ctrl);
 
   return err;
 }
@@ -1841,7 +1841,7 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs)
 
 
 /* Loop over all URLs in STRLIST and fetch the key at that URL.  Note
-   that the fetch operation ignores the configured key servers and
+   that the fetch operation ignores the configured keyservers and
    instead directly retrieves the keys.  */
 int
 keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
@@ -1885,7 +1885,7 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
   /* If the original options didn't have fast import, and the trustdb
      is dirty, rebuild. */
   if (!(opt.keyserver_options.import_options&IMPORT_FAST))
-    check_or_update_trustdb ();
+    check_or_update_trustdb (ctrl);
 
   return 0;
 }
index 5b5947e..7b716ff 100644 (file)
@@ -287,6 +287,8 @@ void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 void keyedit_passwd (ctrl_t ctrl, const char *username);
 void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
                            const char *newuid);
+void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
+                           const char *usagestr, const char *expirestr);
 void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
                          strlist_t uids, strlist_t locusr, int local);
 void show_basic_key_info (KBNODE keyblock);
@@ -296,7 +298,8 @@ u32 parse_expire_string(const char *string);
 u32 ask_expire_interval(int object,const char *def_expire);
 u32 ask_expiredate(void);
 unsigned int ask_key_flags (int algo, int subkey, unsigned int current);
-void quick_generate_keypair (ctrl_t ctrl, const char *uid);
+void quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
+                             const char *usagestr, const char *expirestr);
 void generate_keypair (ctrl_t ctrl, int full, const char *fname,
                        const char *card_serialno, int card_backup_key);
 int keygen_set_std_prefs (const char *string,int personal);
@@ -311,7 +314,10 @@ int keygen_add_revkey(PKT_signature *sig, void *opaque);
 gpg_error_t make_backsig (PKT_signature *sig, PKT_public_key *pk,
                           PKT_public_key *sub_pk, PKT_public_key *sub_psk,
                           u32 timestamp, const char *cache_nonce);
-gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock);
+gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock,
+                                 const char *algostr,
+                                 const char *usagestr,
+                                 const char *expirestr);
 #ifdef ENABLE_CARD_SUPPORT
 gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
                                       int keyno, const char *serialno);
@@ -383,6 +389,7 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
                                   void **r_data, size_t *r_datalen);
 
 gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
+                                       int cleartext,
                                        char **cache_nonce_addr, const char *hexgrip,
                                        PKT_public_key *pk);
 
@@ -420,6 +427,7 @@ char *format_seckey_info (PKT_public_key *pk);
 void print_seckey_info (PKT_public_key *pk);
 void print_pubkey_info (estream_t fp, PKT_public_key *pk);
 void print_card_key_info (estream_t fp, KBNODE keyblock);
+void print_key_line (estream_t fp, PKT_public_key *pk, int secret);
 
 /*-- verify.c --*/
 void print_file_status( int status, const char *name, int what );
index d56790b..453d1b0 100644 (file)
@@ -985,13 +985,10 @@ print_userid (PACKET *pkt)
 static void
 list_node (CTX c, kbnode_t node)
 {
-  int mainkey;
-  char pkstrbuf[PUBKEY_STRING_SIZE];
-
   if (!node)
     ;
-  else if ((mainkey = (node->pkt->pkttype == PKT_PUBLIC_KEY))
-           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+  else if (node->pkt->pkttype == PKT_PUBLIC_KEY
+           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
     {
       PKT_public_key *pk = node->pkt->pkt.public_key;
 
@@ -1000,10 +997,10 @@ list_node (CTX c, kbnode_t node)
           u32 keyid[2];
 
           keyid_from_pk( pk, keyid );
-          if (mainkey)
+          if (pk->flags.primary)
             c->trustletter = (opt.fast_list_mode?
-                              0 : get_validity_info( pk, NULL));
-          es_printf ("%s:", mainkey? "pub":"sub" );
+                              0 : get_validity_info (c->ctrl, pk, NULL));
+          es_printf ("%s:", pk->flags.primary? "pub":"sub" );
           if (c->trustletter)
             es_putc (c->trustletter, es_stdout);
           es_printf (":%u:%d:%08lX%08lX:%s:%s::",
@@ -1012,33 +1009,19 @@ list_node (CTX c, kbnode_t node)
                      (ulong)keyid[0],(ulong)keyid[1],
                      colon_datestr_from_pk( pk ),
                      colon_strtime (pk->expiredate) );
-          if (mainkey && !opt.fast_list_mode)
+          if (pk->flags.primary && !opt.fast_list_mode)
             es_putc (get_ownertrust_info (pk), es_stdout);
           es_putc (':', es_stdout);
+          es_putc ('\n', es_stdout);
         }
       else
-        es_printf ("%s  %s/%s %s",
-                   mainkey? "pub":"sub",
-                   pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
-                   keystr_from_pk (pk),
-                   datestr_from_pk (pk));
-
-      if (pk->flags.revoked)
-        {
-          es_printf (" [");
-          es_printf (_("revoked: %s"), revokestr_from_pk (pk));
-          es_printf ("]\n");
-        }
-      else if( pk->expiredate && !opt.with_colons)
         {
-          es_printf (" [");
-          es_printf (_("expires: %s"), expirestr_from_pk (pk));
-          es_printf ("]\n");
+          print_key_line (es_stdout, pk, 0);
         }
-      else
-        es_putc ('\n', es_stdout);
 
-      if ((mainkey && opt.fingerprint) || opt.fingerprint > 1)
+      if (opt.keyid_format == KF_NONE && !opt.with_colons)
+        ; /* Already printed.  */
+      else if ((pk->flags.primary && opt.fingerprint) || opt.fingerprint > 1)
         print_fingerprint (NULL, pk, 0);
 
       if (opt.with_colons)
@@ -1048,8 +1031,10 @@ list_node (CTX c, kbnode_t node)
                        node->next->pkt->pkt.ring_trust->trustval);
         }
 
-      if (mainkey)
+      if (pk->flags.primary)
         {
+          int kl = opt.keyid_format == KF_NONE? 0 : keystrlen ();
+
           /* Now list all userids with their signatures. */
           for (node = node->next; node; node = node->next)
             {
@@ -1064,7 +1049,7 @@ list_node (CTX c, kbnode_t node)
                                node->pkt->pkt.user_id->attrib_data?"uat":"uid");
                   else
                     es_printf ("uid%*s",
-                               (int)keystrlen ()+(opt.legacy_list_mode? 9:11),
+                               kl + (opt.legacy_list_mode? 9:11),
                                "" );
                   print_userid (node->pkt);
                   if (opt.with_colons)
@@ -1086,7 +1071,7 @@ list_node (CTX c, kbnode_t node)
             }
         }
     }
-  else if ((mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
+  else if (node->pkt->pkttype == PKT_SECRET_KEY
            || node->pkt->pkttype == PKT_SECRET_SUBKEY)
     {
 
@@ -1556,6 +1541,19 @@ pka_uri_from_sig (CTX c, PKT_signature *sig)
 }
 
 
+/* Return true if the AKL has the WKD method specified.  */
+static int
+akl_has_wkd_method (void)
+{
+  struct akl *akl;
+
+  for (akl = opt.auto_key_locate; akl; akl = akl->next)
+    if (akl->type == AKL_WKD)
+      return 1;
+  return 0;
+}
+
+
 static void
 print_good_bad_signature (int statno, const char *keyid_str, kbnode_t un,
                           PKT_signature *sig, int rc)
@@ -1603,31 +1601,31 @@ check_sig_and_print (CTX c, kbnode_t node)
     }
 
   /* Check that the message composition is valid.
-
-     Per RFC-2440bis (-15) allowed:
-
-     S{1,n}           -- detached signature.
-     S{1,n} P         -- old style PGP2 signature
-     O{1,n} P S{1,n}  -- standard OpenPGP signature.
-     C P S{1,n}       -- cleartext signature.
-
-
-          O = One-Pass Signature packet.
-          S = Signature packet.
-          P = OpenPGP Message packet (Encrypted | Compressed | Literal)
-                 (Note that the current rfc2440bis draft also allows
-                  for a signed message but that does not work as it
-                  introduces ambiguities.)
-              We keep track of these packages using the marker packet
-              CTRLPKT_PLAINTEXT_MARK.
-          C = Marker packet for cleartext signatures.
-
-     We reject all other messages.
-
-     Actually we are calling this too often, i.e. for verification of
-     each message but better have some duplicate work than to silently
-     introduce a bug here.
-  */
+   *
+   * Per RFC-2440bis (-15) allowed:
+   *
+   * S{1,n}           -- detached signature.
+   * S{1,n} P         -- old style PGP2 signature
+   * O{1,n} P S{1,n}  -- standard OpenPGP signature.
+   * C P S{1,n}       -- cleartext signature.
+   *
+   *
+   *      O = One-Pass Signature packet.
+   *      S = Signature packet.
+   *      P = OpenPGP Message packet (Encrypted | Compressed | Literal)
+   *             (Note that the current rfc2440bis draft also allows
+   *              for a signed message but that does not work as it
+   *              introduces ambiguities.)
+   *          We keep track of these packages using the marker packet
+   *          CTRLPKT_PLAINTEXT_MARK.
+   *      C = Marker packet for cleartext signatures.
+   *
+   * We reject all other messages.
+   *
+   * Actually we are calling this too often, i.e. for verification of
+   * each message but better have some duplicate work than to silently
+   * introduce a bug here.
+   */
   {
     kbnode_t n;
     int n_onepass, n_sig;
@@ -1712,14 +1710,18 @@ check_sig_and_print (CTX c, kbnode_t node)
       }
   }
 
-  write_status_text (STATUS_NEWSIG, NULL);
+  if (sig->signers_uid)
+    write_status_buffer (STATUS_NEWSIG,
+                         sig->signers_uid, strlen (sig->signers_uid), 0);
+  else
+    write_status_text (STATUS_NEWSIG, NULL);
 
   astr = openpgp_pk_algo_name ( sig->pubkey_algo );
   if (keystrlen () > 8)
     {
       log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp));
       log_info (_("               using %s key %s\n"),
-                astr? astr: "?",keystr(sig->keyid));
+                astr? astr: "?", keystr(sig->keyid));
     }
   else
     log_info (_("Signature made %s using %s key ID %s\n"),
@@ -1728,8 +1730,7 @@ check_sig_and_print (CTX c, kbnode_t node)
 
   rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
 
-  /* If the key isn't found, check for a preferred keyserver */
-
+  /* If the key isn't found, check for a preferred keyserver.  */
   if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
     {
       const byte *p;
@@ -1770,8 +1771,8 @@ check_sig_and_print (CTX c, kbnode_t node)
         }
     }
 
-  /* If the preferred keyserver thing above didn't work, our second
-     try is to use the URI from a DNS PKA record. */
+  /* If the avove methods didn't work, our next try is to use the URI
+   * from a DNS PKA record.  */
   if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
       && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
       && (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD))
@@ -1790,17 +1791,55 @@ check_sig_and_print (CTX c, kbnode_t node)
             {
               glo_ctrl.in_auto_key_retrieve++;
               res = keyserver_import_keyid (c->ctrl, sig->keyid, spec);
-                glo_ctrl.in_auto_key_retrieve--;
-                free_keyserver_spec (spec);
-                if (!res)
-                  rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+              glo_ctrl.in_auto_key_retrieve--;
+              free_keyserver_spec (spec);
+              if (!res)
+                rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
             }
         }
     }
 
-  /* If the preferred keyserver thing above didn't work and we got
-       no information from the DNS PKA, this is a third try. */
+  /* If the above methods didn't work, our next try is to use locate
+   * the key via its fingerprint from a keyserver.  This requires
+   * that the signers fingerprint is encoded in the signature.  We
+   * favor this over the WKD method (to be tried next), because an
+   * arbitrary keyserver is less subject to web bug like
+   * monitoring.  */
+  /* if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY */
+  /*     && signature_hash_full_fingerprint (sig) */
+  /*     && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) */
+  /*     && keyserver_any_configured (c->ctrl)) */
+  /*   { */
+  /*     int res; */
+
+  /*     glo_ctrl.in_auto_key_retrieve++; */
+  /*     res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); */
+  /*     glo_ctrl.in_auto_key_retrieve--; */
+  /*     if (!res) */
+  /*       rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); */
+  /*   } */
+
+  /* If the above methods didn't work, our next try is to retrieve the
+   * key from the WKD. */
+  if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
+      && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
+      && !opt.flags.disable_signer_uid
+      && akl_has_wkd_method ()
+      && sig->signers_uid)
+    {
+      int res;
+
+      glo_ctrl.in_auto_key_retrieve++;
+      res = keyserver_import_wkd (c->ctrl, sig->signers_uid, NULL, NULL);
+      glo_ctrl.in_auto_key_retrieve--;
+      /* Fixme: If the fingerprint is embedded in the signature,
+       * compare it to the fingerprint of the returned key.  */
+      if (!res)
+        rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+    }
 
+  /* If the above methods did't work, our next try is to use a
+   * keyserver.  */
   if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
       && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
       && keyserver_any_configured (c->ctrl))
@@ -1808,7 +1847,7 @@ check_sig_and_print (CTX c, kbnode_t node)
       int res;
 
       glo_ctrl.in_auto_key_retrieve++;
-      res=keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver );
+      res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver );
       glo_ctrl.in_auto_key_retrieve--;
       if (!res)
         rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
@@ -1871,7 +1910,7 @@ check_sig_and_print (CTX c, kbnode_t node)
             does not print a LF we need to compute the validity
             before calling that function.  */
           if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY))
-            valid = get_validity (pk, un->pkt->pkt.user_id, NULL, 0);
+            valid = get_validity (c->ctrl, pk, un->pkt->pkt.user_id, NULL, 0);
           else
             valid = 0; /* Not used.  */
 
@@ -1950,7 +1989,8 @@ check_sig_and_print (CTX c, kbnode_t node)
                   dump_attribs (un->pkt->pkt.user_id, pk);
 
                   if (opt.verify_options&VERIFY_SHOW_PHOTOS)
-                    show_photos (un->pkt->pkt.user_id->attribs,
+                    show_photos (c->ctrl,
+                                 un->pkt->pkt.user_id->attribs,
                                  un->pkt->pkt.user_id->numattribs,
                                  pk ,un->pkt->pkt.user_id);
                 }
@@ -1973,7 +2013,8 @@ check_sig_and_print (CTX c, kbnode_t node)
                       actually ask the user to update any trust
                       information.  */
                     valid = (trust_value_to_string
-                             (get_validity (pk, un->pkt->pkt.user_id, sig, 0)));
+                             (get_validity (c->ctrl, pk,
+                                            un->pkt->pkt.user_id, sig, 0)));
                   log_printf (" [%s]\n",valid);
                 }
               else
@@ -2061,7 +2102,7 @@ check_sig_and_print (CTX c, kbnode_t node)
         {
           if ((opt.verify_options & VERIFY_PKA_LOOKUPS))
             pka_uri_from_sig (c, sig); /* Make sure PKA info is available. */
-          rc = check_signatures_trust (sig);
+          rc = check_signatures_trust (c->ctrl, sig);
         }
 
       /* Print extra information about the signature.  */
index f4881b4..a9da5a0 100644 (file)
@@ -49,10 +49,10 @@ migrate_secring (ctrl_t ctrl)
   char *flagfile = NULL;
   char *agent_version = NULL;
 
-  secring = make_filename (opt.homedir, "secring" EXTSEP_S "gpg", NULL);
+  secring = make_filename (gnupg_homedir (), "secring" EXTSEP_S "gpg", NULL);
   if (access (secring, F_OK))
     goto leave; /* Does not exist or is not readable.  */
-  flagfile = make_filename (opt.homedir, V21_MIGRATION_FNAME, NULL);
+  flagfile = make_filename (gnupg_homedir (), V21_MIGRATION_FNAME, NULL);
   if (!access (flagfile, F_OK))
     goto leave; /* Does exist - fine.  */
 
index 0de0418..0a87b90 100644 (file)
@@ -71,6 +71,7 @@ struct
   int with_key_data;
   int with_icao_spelling; /* Print ICAO spelling with fingerprints.  */
   int with_fingerprint; /* Option --with-fingerprint active.  */
+  int with_subkey_fingerprint; /* Option --with-subkey-fingerprint active.  */
   int with_keygrip;     /* Option --with-keygrip active.  */
   int with_secret;      /* Option --with-secret active.  */
   int with_wkd_hash;    /* Option --with-wkd-hash.  */
@@ -105,7 +106,6 @@ struct
   int marginals_needed;
   int completes_needed;
   int max_cert_depth;
-  const char *homedir;
   const char *agent_program;
   const char *dirmngr_program;
 
@@ -137,7 +137,7 @@ struct
     } compliance;
   enum
     {
-      KF_DEFAULT, KF_SHORT, KF_LONG, KF_0xSHORT, KF_0xLONG
+      KF_DEFAULT, KF_NONE, KF_SHORT, KF_LONG, KF_0xSHORT, KF_0xLONG
     } keyid_format;
   int shm_coprocess;
   const char *set_filename;
@@ -234,6 +234,7 @@ struct
     unsigned int allow_multiple_messages:1;
     unsigned int allow_weak_digest_algos:1;
     unsigned int large_rsa:1;
+    unsigned int disable_signer_uid:1;
   } flags;
 
   /* Linked list of ways to find a key if the key isn't on the local
@@ -290,7 +291,7 @@ struct {
 #define DBG_IPC_VALUE     1024  /* debug assuan communication */
 #define DBG_CARD_IO_VALUE 2048  /* debug smart card I/O.  */
 #define DBG_CLOCK_VALUE   4096
-#define DBG_LOOKUP_VALUE  8192 /* debug the kety lookup */
+#define DBG_LOOKUP_VALUE  8192 /* debug the key lookup */
 #define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
 
 /* Tests for the debugging flags.  */
index 194c134..8fb6fc4 100644 (file)
@@ -230,6 +230,8 @@ typedef struct
   int numrevkeys;
   pka_info_t *pka_info;      /* Malloced PKA data or NULL if not
                                 available.  See also flags.pka_tried. */
+  char *signers_uid;         /* Malloced value of the SIGNERS_UID
+                              * subpacket.  */
   subpktarea_t *hashed;      /* All subpackets with hashed data (v4 only). */
   subpktarea_t *unhashed;    /* Ditto for unhashed data. */
   /* First 2 bytes of the digest.  (Serialized.  Note: this is not
@@ -531,12 +533,14 @@ struct notation
   /* The notation's name.  */
   char *name;
   /* If the notation is human readable, then the value is stored here
-     as a NUL-terminated string.  */
+     as a NUL-terminated string.  If it is not human readable a human
+     readable approximation of the binary value _may_ be stored
+     here.  */
   char *value;
   /* Sometimes we want to %-expand the value.  In these cases, we save
      that transformed value here.  */
   char *altvalue;
-  /* If the notation is not human readable, then the value is strored
+  /* If the notation is not human readable, then the value is stored
      here.  */
   unsigned char *bdat;
   /* The amount of data stored in BDAT.
@@ -552,6 +556,8 @@ struct notation
   {
     /* The notation is critical.  */
     unsigned int critical:1;
+    /* The notation is human readable.  */
+    unsigned int human:1;
     /* The notation should be deleted.  */
     unsigned int ignore:1;
   } flags;
@@ -559,6 +565,7 @@ struct notation
   /* A field to facilitate creating a list of notations.  */
   struct notation *next;
 };
+typedef struct notation *notation_t;
 
 /*-- mainproc.c --*/
 void reset_literals_seen(void);
index c77e409..e02238b 100644 (file)
@@ -1374,12 +1374,12 @@ dump_sig_subpkt (int hashed, int type, int critical,
        es_fprintf (listfp, " %d", buffer[i]);
       break;
     case SIGSUBPKT_KS_FLAGS:
-      es_fputs ("key server preferences:", listfp);
+      es_fputs ("keyserver preferences:", listfp);
       for (i = 0; i < length; i++)
        es_fprintf (listfp, " %02X", buffer[i]);
       break;
     case SIGSUBPKT_PREF_KS:
-      es_fputs ("preferred key server: ", listfp);
+      es_fputs ("preferred keyserver: ", listfp);
       es_write_sanitized (listfp, buffer, length, ")", NULL);
       break;
     case SIGSUBPKT_PRIMARY_UID:
@@ -1915,6 +1915,20 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
       if (p)
        sig->flags.pref_ks = 1;
 
+      p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len);
+      if (p && len)
+        {
+          sig->signers_uid = xtrymalloc (len+1);
+          if (!sig->signers_uid)
+            {
+              rc = gpg_error_from_syserror ();
+              goto leave;
+            }
+          /* Note that we don't care about binary zeroes in the value.  */
+          memcpy (sig->signers_uid, p, len);
+          sig->signers_uid[len] = 0;
+        }
+
       p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL);
       if (p)
        sig->flags.notation = 1;
index f6e625a..e188653 100644 (file)
@@ -48,7 +48,7 @@
 /* Generate a new photo id packet, or return NULL if canceled.
    FIXME:  Should we add a duplicates check similar to generate_user_id? */
 PKT_user_id *
-generate_photo_id(PKT_public_key *pk,const char *photo_name)
+generate_photo_id (ctrl_t ctrl, PKT_public_key *pk,const char *photo_name)
 {
   PKT_user_id *uid;
   int error=1,i;
@@ -163,7 +163,7 @@ generate_photo_id(PKT_public_key *pk,const char *photo_name)
          "user" may not be able to dismiss a viewer window! */
       if(opt.command_fd==-1)
        {
-         show_photos (uid->attribs, uid->numattribs, pk, uid);
+         show_photos (ctrl, uid->attribs, uid->numattribs, pk, uid);
          switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
                                         _("Is this photo correct (y/N/q)? ")))
            {
@@ -286,9 +286,10 @@ static const char *get_default_photo_command(void)
 }
 #endif
 
+
 void
-show_photos(const struct user_attribute *attrs, int count,
-            PKT_public_key *pk, PKT_user_id *uid)
+show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
+             PKT_public_key *pk, PKT_user_id *uid)
 {
 #ifdef DISABLE_PHOTO_VIEWER
   (void)attrs;
@@ -303,8 +304,8 @@ show_photos(const struct user_attribute *attrs, int count,
 
   memset (&args, 0, sizeof(args));
   args.pk = pk;
-  args.validity_info = get_validity_info (pk, uid);
-  args.validity_string = get_validity_string (pk, uid);
+  args.validity_info = get_validity_info (ctrl, pk, uid);
+  args.validity_string = get_validity_string (ctrl, pk, uid);
   namehash_from_uid (uid);
   args.namehash = uid->namehash;
 
index ec2b55f..9fc758e 100644 (file)
 
 #include "packet.h"
 
-PKT_user_id *generate_photo_id(PKT_public_key *pk,const char *filename);
+PKT_user_id *generate_photo_id (ctrl_t ctrl,
+                                PKT_public_key *pk,const char *filename);
 int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len);
 char *image_type_to_string(byte type,int style);
-void show_photos (const struct user_attribute *attrs, int count,
+void show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
                   PKT_public_key *pk, PKT_user_id *uid);
 
 #endif /* !_PHOTOID_H_ */
index de8897a..8efa954 100644 (file)
@@ -178,7 +178,7 @@ show_revocation_reason( PKT_public_key *pk, int mode )
  */
 #ifndef NO_TRUST_MODELS
 static int
-do_edit_ownertrust (PKT_public_key *pk, int mode,
+do_edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode,
                     unsigned *new_trust, int defer_help )
 {
   char *p;
@@ -189,7 +189,6 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
   int min_num;
   int did_help=defer_help;
   unsigned int minimum = tdb_get_min_ownertrust (pk);
-  char pkstrbuf[PUBKEY_STRING_SIZE];
 
   switch(minimum)
     {
@@ -222,13 +221,12 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
           {
             KBNODE keyblock, un;
 
-            tty_printf(_("No trust value assigned to:\n"));
-           tty_printf("%s/%s %s\n",
-                       pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
-                       keystr(keyid), datestr_from_pk( pk ) );
-           p=get_user_id_native(keyid);
-           tty_printf(_("      \"%s\"\n"),p);
-           xfree(p);
+            tty_printf (_("No trust value assigned to:\n"));
+            print_key_line (NULL, pk, 0);
+
+           p = get_user_id_native(keyid);
+           tty_printf (_("      \"%s\"\n"),p);
+           xfree (p);
 
             keyblock = get_pubkeyblock (keyid);
             if (!keyblock)
@@ -248,7 +246,8 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
 
                if((opt.verify_options&VERIFY_SHOW_PHOTOS)
                   && un->pkt->pkt.user_id->attrib_data)
-                 show_photos (un->pkt->pkt.user_id->attribs,
+                 show_photos (ctrl,
+                               un->pkt->pkt.user_id->attribs,
                                un->pkt->pkt.user_id->numattribs, pk,
                                un->pkt->pkt.user_id);
 
@@ -376,14 +375,14 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
  */
 #ifndef NO_TRUST_MODELS
 int
-edit_ownertrust (PKT_public_key *pk, int mode )
+edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode )
 {
   unsigned int trust = 0;
   int no_help = 0;
 
   for(;;)
     {
-      switch ( do_edit_ownertrust (pk, mode, &trust, no_help ) )
+      switch ( do_edit_ownertrust (ctrl, pk, mode, &trust, no_help ) )
         {
         case -1: /* quit */
           return -1;
@@ -526,7 +525,7 @@ write_trust_status (int statuscode, int trustlevel)
  * Returns an error code if we should not trust this signature.
  */
 int
-check_signatures_trust( PKT_signature *sig )
+check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
 {
   PKT_public_key *pk = xmalloc_clear( sizeof *pk );
   unsigned int trustlevel = TRUST_UNKNOWN;
@@ -553,7 +552,7 @@ check_signatures_trust( PKT_signature *sig )
     log_info(_("WARNING: this key might be revoked (revocation key"
               " not present)\n"));
 
-  trustlevel = get_validity (pk, NULL, sig, 1);
+  trustlevel = get_validity (ctrl, pk, NULL, sig, 1);
 
   if ( (trustlevel & TRUST_FLAG_REVOKED) )
     {
@@ -845,7 +844,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     }
 
   /* Key found and usable.  Check validity. */
-  trustlevel = get_validity (pk, pk->user_id, NULL, 1);
+  trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
   if ( (trustlevel & TRUST_FLAG_DISABLED) )
     {
       /* Key has been disabled. */
@@ -1183,7 +1182,7 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
                 { /* Check validity of this key. */
                   int trustlevel;
 
-                  trustlevel = get_validity (pk, pk->user_id, NULL, 1);
+                  trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
                   if ( (trustlevel & TRUST_FLAG_DISABLED) )
                     {
                       tty_printf (_("Public key is disabled.\n") );
index 21810a4..a1027b8 100644 (file)
@@ -71,6 +71,49 @@ release_progress_context (progress_filter_context_t *pfx)
 }
 
 
+static void
+write_status_progress (const char *what,
+                       unsigned long current, unsigned long total)
+{
+  char buffer[50];
+
+  /* Although we use an unsigned long for the values, 32 bit
+   * applications using GPGME will use an "int" and thus are limited
+   * in the total size which can be represented.  On Windows, where
+   * sizeof(int)==sizeof(long), this is even worse and will lead to an
+   * integer overflow for all files larger than 2 GiB.  Although, the
+   * allowed value range of TOTAL and CURRENT is nowhere specified, we
+   * better protect applications from the need to handle negative
+   * values.  The common usage pattern of the progress information is
+   * to display how many percent of the operation has been done and
+   * thus scaling CURRENT and TOTAL down before they get to large,
+   * should not have a noticeable effect except for rounding
+   * imprecision. */
+  if (total)
+    {
+      if (current > total)
+        current = total;
+
+      while (total > 1024*1024)
+        {
+          total /= 1024;
+          current /= 1024;
+        }
+    }
+  else
+    {
+      while (current > 1024*1024)
+        {
+          current /= 1024;
+        }
+    }
+
+  snprintf (buffer, sizeof buffer, "%.20s ? %lu %lu",
+            what? what : "?", current, total);
+  write_status_text (STATUS_PROGRESS, buffer);
+}
+
+
 /****************
  * The filter is used to report progress to the user.
  */
@@ -83,17 +126,11 @@ progress_filter (void *opaque, int control,
 
   if (control == IOBUFCTRL_INIT)
     {
-      char buffer[50];
-
       pfx->last = 0;
       pfx->offset = 0;
       pfx->last_time = make_timestamp ();
 
-      sprintf (buffer, "%.20s ? %lu %lu",
-               pfx->what? pfx->what : "?",
-               pfx->offset,
-              pfx->total);
-      write_status_text (STATUS_PROGRESS, buffer);
+      write_status_progress (pfx->what, pfx->offset, pfx->total);
     }
   else if (control == IOBUFCTRL_UNDERFLOW)
     {
@@ -113,14 +150,7 @@ progress_filter (void *opaque, int control,
       if ((len == -1 && pfx->offset != pfx->last)
          || timestamp - pfx->last_time > 0)
        {
-         char buffer[50];
-
-         sprintf (buffer, "%.20s ? %lu %lu",
-                   pfx->what? pfx->what : "?",
-                   pfx->offset,
-                  pfx->total);
-         write_status_text (STATUS_PROGRESS, buffer);
-
+          write_status_progress (pfx->what, pfx->offset, pfx->total);
          pfx->last = pfx->offset;
          pfx->last_time = timestamp;
        }
index 3c6e158..218ca59 100644 (file)
@@ -530,10 +530,10 @@ gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
   void *leadin;
   size_t len;
   u32 keyid[2];
-  char pkstrbuf[PUBKEY_STRING_SIZE];
+  int kl;
   char *orig_codeset;
 
-  dir = get_openpgp_revocdir (opt.homedir);
+  dir = get_openpgp_revocdir (gnupg_homedir ());
   tmpstr = hexfingerprint (psk, NULL, 0);
   fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL);
   xfree (tmpstr);
@@ -550,16 +550,16 @@ gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
   es_fprintf (memfp, "%s\n\n",
               _("This is a revocation certificate for the OpenPGP key:"));
 
-  es_fprintf (memfp, "pub  %s/%s %s\n",
-              pubkey_string (psk, pkstrbuf, sizeof pkstrbuf),
-              keystr (keyid),
-              datestr_from_pk (psk));
+  print_key_line (memfp, psk, 0);
 
-  print_fingerprint (memfp, psk, 3);
+  if (opt.keyid_format != KF_NONE)
+    print_fingerprint (memfp, psk, 3);
+
+  kl = opt.keyid_format == KF_NONE? 0 : keystrlen ();
 
   tmpstr = get_user_id (keyid, &len);
   es_fprintf (memfp, "uid%*s%.*s\n\n",
-              (int)keystrlen () + 10, "",
+              kl + 10, "",
               (int)len, tmpstr);
   xfree (tmpstr);
 
index 9ec263f..771a8a7 100644 (file)
@@ -695,12 +695,12 @@ gpg_server (ctrl_t ctrl)
   assuan_set_pointer (ctx, ctrl);
   if (opt.verbose || opt.debug)
     {
-      char *tmp = NULL;
+      char *tmp;
 
       tmp = xtryasprintf ("Home: %s\n"
                           "Config: %s\n"
                           "%s",
-                          opt.homedir,
+                          gnupg_homedir (),
                           "fixme: need config filename",
                           hello);
       if (tmp)
index c41a145..e5385af 100644 (file)
@@ -211,9 +211,12 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits,
     int i,n;
     gcry_mpi_t a;
 
-    if( len + asnlen + 4  > nframe )
-      log_bug ("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
-               (int)(len*8), (int)nbits, algo);
+    if (len + asnlen + 4  > nframe)
+      {
+        log_error ("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
+                   (int)(len*8), (int)nbits, algo);
+        return NULL;
+      }
 
     /* We encode the MD in this way:
      *
index 290f19a..7000b48 100644 (file)
@@ -797,15 +797,20 @@ check_signature_over_key_or_uid (PKT_public_key *signer,
             *is_selfsig = 1;
         }
       else
-        /* See if one of the subkeys was the signer (although this is
-           extremely unlikely).  */
         {
           kbnode_t ctx = NULL;
           kbnode_t n;
 
-          while ((n = walk_kbnode (kb, &ctx, PKT_PUBLIC_SUBKEY)))
+          /* See if one of the subkeys was the signer (although this
+             is extremely unlikely).  */
+          while ((n = walk_kbnode (kb, &ctx, 0)))
             {
-              PKT_public_key *subk = n->pkt->pkt.public_key;
+              PKT_public_key *subk;
+
+              if (n->pkt->pkttype != PKT_PUBLIC_SUBKEY)
+                continue;
+
+              subk = n->pkt->pkt.public_key;
               if (sig->keyid[0] == subk->keyid[0]
                   && sig->keyid[1] == subk->keyid[1])
                 /* Issued by a subkey.  */
index 364634a..a4974be 100644 (file)
@@ -40,7 +40,7 @@
 #include "pkglue.h"
 #include "sysutils.h"
 #include "call-agent.h"
-
+#include "mbox-util.h"
 
 #ifdef HAVE_DOSISH_SYSTEM
 #define LF "\r\n"
@@ -59,92 +59,105 @@ static void
 mk_notation_policy_etc (PKT_signature *sig,
                        PKT_public_key *pk, PKT_public_key *pksk)
 {
-    const char *string;
-    char *s=NULL;
-    strlist_t pu=NULL;
-    struct notation *nd=NULL;
-    struct expando_args args;
+  const char *string;
+  char *p = NULL;
+  strlist_t pu = NULL;
+  struct notation *nd = NULL;
+  struct expando_args args;
 
-    log_assert(sig->version>=4);
+  log_assert (sig->version >= 4);
 
-    memset(&args,0,sizeof(args));
-    args.pk=pk;
-    args.pksk=pksk;
+  memset (&args, 0, sizeof(args));
+  args.pk = pk;
+  args.pksk = pksk;
 
-    /* notation data */
-    if(IS_SIG(sig) && opt.sig_notations)
-      nd=opt.sig_notations;
-    else if( IS_CERT(sig) && opt.cert_notations )
-      nd=opt.cert_notations;
+  /* Notation data. */
+  if (IS_SIG(sig) && opt.sig_notations)
+    nd = opt.sig_notations;
+  else if (IS_CERT(sig) && opt.cert_notations)
+    nd = opt.cert_notations;
 
-    if(nd)
-      {
-       struct notation *i;
+  if (nd)
+    {
+      struct notation *item;
 
-       for(i=nd;i;i=i->next)
-         {
-           i->altvalue=pct_expando(i->value,&args);
-           if(!i->altvalue)
-             log_error(_("WARNING: unable to %%-expand notation "
-                         "(too large).  Using unexpanded.\n"));
-         }
+      for (item = nd; item; item = item->next)
+        {
+          item->altvalue = pct_expando (item->value,&args);
+          if (!item->altvalue)
+            log_error (_("WARNING: unable to %%-expand notation "
+                         "(too large).  Using unexpanded.\n"));
+        }
 
-       keygen_add_notations(sig,nd);
+      keygen_add_notations (sig, nd);
 
-       for(i=nd;i;i=i->next)
-         {
-           xfree(i->altvalue);
-           i->altvalue=NULL;
-         }
-      }
+      for (item = nd; item; item = item->next)
+        {
+          xfree (item->altvalue);
+          item->altvalue = NULL;
+        }
+    }
 
-    /* set policy URL */
-    if( IS_SIG(sig) && opt.sig_policy_url )
-      pu=opt.sig_policy_url;
-    else if( IS_CERT(sig) && opt.cert_policy_url )
-      pu=opt.cert_policy_url;
+  /* Set policy URL. */
+  if (IS_SIG(sig) && opt.sig_policy_url)
+    pu = opt.sig_policy_url;
+  else if (IS_CERT(sig) && opt.cert_policy_url)
+    pu = opt.cert_policy_url;
 
-    for(;pu;pu=pu->next)
-      {
-        string = pu->d;
+  for (; pu; pu = pu->next)
+    {
+      string = pu->d;
 
-       s=pct_expando(string,&args);
-       if(!s)
-         {
-           log_error(_("WARNING: unable to %%-expand policy URL "
-                       "(too large).  Using unexpanded.\n"));
-           s=xstrdup(string);
-         }
+      p = pct_expando (string, &args);
+      if (!p)
+        {
+          log_error(_("WARNING: unable to %%-expand policy URL "
+                      "(too large).  Using unexpanded.\n"));
+          p = xstrdup(string);
+        }
 
-       build_sig_subpkt(sig,SIGSUBPKT_POLICY|
-                        ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
-                        s,strlen(s));
+      build_sig_subpkt (sig, (SIGSUBPKT_POLICY
+                              | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)),
+                        p, strlen (p));
 
-       xfree(s);
-      }
+      xfree (p);
+    }
 
-    /* preferred keyserver URL */
-    if( IS_SIG(sig) && opt.sig_keyserver_url )
-      pu=opt.sig_keyserver_url;
+  /* Preferred keyserver URL. */
+  if (IS_SIG(sig) && opt.sig_keyserver_url)
+    pu = opt.sig_keyserver_url;
 
-    for(;pu;pu=pu->next)
-      {
-        string = pu->d;
+  for (; pu; pu = pu->next)
+    {
+      string = pu->d;
 
-       s=pct_expando(string,&args);
-       if(!s)
-         {
-           log_error(_("WARNING: unable to %%-expand preferred keyserver URL"
-                       " (too large).  Using unexpanded.\n"));
-           s=xstrdup(string);
-         }
+      p = pct_expando (string, &args);
+      if (!p)
+        {
+          log_error (_("WARNING: unable to %%-expand preferred keyserver URL"
+                       " (too large).  Using unexpanded.\n"));
+          p = xstrdup (string);
+        }
 
-       build_sig_subpkt(sig,SIGSUBPKT_PREF_KS|
-                        ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
-                        s,strlen(s));
+      build_sig_subpkt (sig, (SIGSUBPKT_PREF_KS
+                              | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)),
+                        p, strlen (p));
+      xfree (p);
+    }
 
-       xfree(s);
-      }
+  /* Set signer's user id.  */
+  if (IS_SIG (sig) && !opt.flags.disable_signer_uid)
+    {
+      char *mbox;
+
+      /* For now we use the uid which was used to locate the key.  */
+      if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name)))
+        {
+          if (DBG_LOOKUP)
+            log_debug ("setting Signer's UID to '%s'\n", mbox);
+          build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox));
+        }
+    }
 }
 
 
@@ -346,7 +359,7 @@ openpgp_card_v1_p (PKT_public_key *pk)
         }
 
       xfree (pk->serialno);
-      agent_get_keyinfo (NULL, hexgrip, &pk->serialno);
+      agent_get_keyinfo (NULL, hexgrip, &pk->serialno, NULL);
       xfree (hexgrip);
       pk->flags.serialno_valid = 1;
     }
diff --git a/g10/sqlite.h b/g10/sqlite.h
deleted file mode 100644 (file)
index 753e37a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* sqlite.h - SQLite helper functions.
- * Copyright (C) 2015 g10 Code GmbH
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GNUPG_SQLITE_H
-#define GNUPG_SQLITE_H
-
-#include <sqlite3.h>
-
-enum sqlite_arg_type
-  {
-    SQLITE_ARG_END = 0xdead001,
-    SQLITE_ARG_INT,
-    SQLITE_ARG_LONG_LONG,
-    SQLITE_ARG_STRING,
-    /* This takes two arguments: the blob as a void * and the length
-       of the blob as a long long.  */
-    SQLITE_ARG_BLOB
-  };
-
-
-int sqlite3_exec_printf (sqlite3 *db,
-                         int (*callback)(void*,int,char**,char**), void *cookie,
-                         char **errmsg,
-                         const char *sql, ...);
-
-typedef int (*sqlite3_stepx_callback) (void *cookie,
-                                       /* number of columns.  */
-                                       int cols,
-                                       /* columns as text.  */
-                                       char **values,
-                                       /* column names.  */
-                                       char **names,
-                                       /* The prepared statement so
-                                          that it is possible to use
-                                          something like
-                                          sqlite3_column_blob().  */
-                                       sqlite3_stmt *statement);
-
-int sqlite3_stepx (sqlite3 *db,
-                   sqlite3_stmt **stmtp,
-                   sqlite3_stepx_callback callback,
-                   void *cookie,
-                   char **errmsg,
-                   const char *sql, ...);
-
-#endif
index 5fdd946..a414709 100644 (file)
@@ -617,14 +617,15 @@ tdbio_set_dbname (const char *new_dbname, int create, int *r_nofile)
 
   if (!new_dbname)
     {
-      fname = make_filename (opt.homedir, "trustdb" EXTSEP_S GPGEXT_GPG, NULL);
+      fname = make_filename (gnupg_homedir (),
+                             "trustdb" EXTSEP_S GPGEXT_GPG, NULL);
     }
   else if (*new_dbname != DIRSEP_C )
     {
       if (strchr (new_dbname, DIRSEP_C))
         fname = make_filename (new_dbname, NULL);
       else
-        fname = make_filename (opt.homedir, new_dbname, NULL);
+        fname = make_filename (gnupg_homedir (), new_dbname, NULL);
     }
   else
     {
index 2edae18..42c91f8 100644 (file)
@@ -58,8 +58,9 @@ g10_exit( int rc )
  * this utility assumes that all keys in the keyring are trustworthy
  */
 int
-check_signatures_trust( PKT_signature *sig )
+check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
 {
+  (void)ctrl;
   (void)sig;
   return 0;
 }
@@ -91,22 +92,25 @@ cache_disabled_value(PKT_public_key *pk)
 }
 
 void
-check_trustdb_stale(void)
+check_trustdb_stale (ctrl_t ctrl)
 {
+  (void)ctrl;
 }
 
 int
-get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
+get_validity_info (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
 {
+  (void)ctrl;
   (void)pk;
   (void)uid;
   return '?';
 }
 
 unsigned int
-get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
-             int may_ask)
+get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
+              PKT_signature *sig, int may_ask)
 {
+  (void)ctrl;
   (void)pk;
   (void)uid;
   (void)sig;
@@ -122,8 +126,9 @@ trust_value_to_string (unsigned int value)
 }
 
 const char *
-uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid)
+uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid)
 {
+  (void)ctrl;
   (void)key;
   (void)uid;
   return "err";
@@ -410,10 +415,12 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
 }
 
 gpg_error_t
-agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
+                   char **r_serialno, int *r_cleartext)
 {
   (void)ctrl;
   (void)hexkeygrip;
+  (void)r_cleartext;
   *r_serialno = NULL;
   return gpg_error (GPG_ERR_NO_SECKEY);
 }
@@ -451,9 +458,10 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
 }
 
 gpg_error_t
-tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id,
                 enum tofu_policy *policy)
 {
+  (void)ctrl;
   (void)pk;
   (void)user_id;
   (void)policy;
index e591aa5..471aec6 100644 (file)
@@ -39,7 +39,7 @@
 #include "ttyio.h"
 #include "trustdb.h"
 #include "mkdir_p.h"
-#include "sqlite.h"
+#include "gpgsql.h"
 #include "status.h"
 
 #include "tofu.h"
@@ -84,8 +84,8 @@ enum db_type
    theis case, NAME is either the normalized email address or the
    fingerprint.
 
-   To initialize this data structure, call opendbs().  When you are
-   done, clean it up using closedbs().  To get a handle to a database,
+   To initialize this data structure, call opendbs().  Cleanup is done
+   when the CTRL object is released.  To get a handle to a database,
    use the getdb() function.  This will either return an existing
    handle or open a new DB connection, as appropriate.  */
 struct db
@@ -262,7 +262,7 @@ begin_transaction (struct db *db, int only_batch)
 
   if (batch_update && ! db->batch_update)
     {
-      rc = sqlite3_stepx (db->db, &db->s.savepoint_batch,
+      rc = gpgsql_stepx (db->db, &db->s.savepoint_batch,
                           NULL, NULL, &err,
                           "savepoint batch;", SQLITE_ARG_END);
       if (rc)
@@ -281,7 +281,7 @@ begin_transaction (struct db *db, int only_batch)
   if (only_batch)
     return 0;
 
-  rc = sqlite3_stepx (db->db, &db->s.savepoint_inner,
+  rc = gpgsql_stepx (db->db, &db->s.savepoint_inner,
                       NULL, NULL, &err,
                       "savepoint inner;", SQLITE_ARG_END);
   if (rc)
@@ -316,7 +316,7 @@ end_transaction (struct db *db, int only_batch)
     {
       db->batch_update = 0;
 
-      rc = sqlite3_stepx (db->db, &db->s.savepoint_batch_commit,
+      rc = gpgsql_stepx (db->db, &db->s.savepoint_batch_commit,
                           NULL, NULL, &err,
                           "release batch;", SQLITE_ARG_END);
       if (rc)
@@ -337,7 +337,7 @@ end_transaction (struct db *db, int only_batch)
   if (only_batch)
     return 0;
 
-  rc = sqlite3_stepx (db->db, &db->s.savepoint_inner_commit,
+  rc = gpgsql_stepx (db->db, &db->s.savepoint_inner_commit,
                       NULL, NULL, &err,
                       "release inner;", SQLITE_ARG_END);
   if (rc)
@@ -640,7 +640,7 @@ initdb (sqlite3 *db, enum db_type type)
    *     know why this occurred, we also set conflict to 0xbaddecaf.
    */
   if (type == DB_EMAIL || type == DB_COMBINED)
-    rc = sqlite3_exec_printf
+    rc = gpgsql_exec_printf
       (db, NULL, NULL, &err,
        "create table bindings\n"
        " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
@@ -659,7 +659,7 @@ initdb (sqlite3 *db, enum db_type type)
 
        Note: since the data is split on the email address, there is no
        need to index the email column.  */
-    rc = sqlite3_exec_printf
+    rc = gpgsql_exec_printf
       (db, NULL, NULL, &err,
        "create table bindings\n"
        " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
@@ -747,7 +747,7 @@ opendb (char *filename, enum db_type type)
       log_assert (! filename);
       log_assert (type == DB_COMBINED);
 
-      filename = make_filename (opt.homedir, "tofu.db", NULL);
+      filename = make_filename (gnupg_homedir (), "tofu.db", NULL);
       filename_free = 1;
     }
   else
@@ -782,7 +782,8 @@ opendb (char *filename, enum db_type type)
   return db;
 }
 
-struct dbs
+/* Definition of the Tofu dabase meta handle.  */
+struct tofu_dbs_s
 {
   struct db *db;
 };
@@ -814,7 +815,7 @@ link_db (struct db **head, struct db *db)
    TYPE must be either DB_MAIL or DB_KEY.  In the combined format, the
    combined DB is always returned.  */
 static struct db *
-getdb (struct dbs *dbs, const char *name, enum db_type type)
+getdb (tofu_dbs_t dbs, const char *name, enum db_type type)
 {
   struct db *t = NULL;
   char *name_sanitized = NULL;
@@ -894,10 +895,10 @@ getdb (struct dbs *dbs, const char *name, enum db_type type)
         char *name_db;
 
         /* Make the directory.  */
-        rc = gnupg_mkdir_p (opt.homedir, "tofu.d", type_str, prefix, NULL);
+        rc = gnupg_mkdir_p (gnupg_homedir (), "tofu.d", type_str, prefix, NULL);
         if (rc)
           {
-            name_db = xstrconcat (opt.homedir, "tofu.d",
+            name_db = xstrconcat (gnupg_homedir (), "tofu.d",
                                   type_str, prefix, NULL);
             log_error (_("can't create directory '%s': %s\n"),
                        name_db, gpg_strerror (rc));
@@ -907,7 +908,7 @@ getdb (struct dbs *dbs, const char *name, enum db_type type)
 
         name_db = xstrconcat (name_sanitized, ".db", NULL);
         filename = make_filename
-          (opt.homedir, "tofu.d", type_str, prefix, name_db, NULL);
+          (gnupg_homedir (), "tofu.d", type_str, prefix, name_db, NULL);
         xfree (name_db);
       }
     }
@@ -980,12 +981,15 @@ closedb (struct db *db)
 /* Create a new DB meta-handle.  Returns NULL on error.  */
 /* FIXME: Change to return an error code for better reporting by the
    caller.  */
-static struct dbs *
-opendbs (void)
+static tofu_dbs_t
+opendbs (ctrl_t ctrl)
 {
+  if (ctrl->tofu.dbs)
+    return ctrl->tofu.dbs;
+
   if (opt.tofu_db_format == TOFU_DB_AUTO)
     {
-      char *filename = make_filename (opt.homedir, "tofu.db", NULL);
+      char *filename = make_filename (gnupg_homedir (), "tofu.db", NULL);
       struct stat s;
       int have_tofu_db = 0;
       int have_tofu_d = 0;
@@ -1045,14 +1049,26 @@ opendbs (void)
        }
     }
 
-  return xmalloc_clear (sizeof (struct dbs));
+  ctrl->tofu.dbs = xmalloc_clear (sizeof (struct tofu_dbs_s));
+  return ctrl->tofu.dbs;
 }
 
+
 /* Release all of the resources associated with a DB meta-handle.  */
-static void
-closedbs (struct dbs *dbs)
+void
+tofu_closedbs (ctrl_t ctrl)
 {
-  if (dbs->db)
+  tofu_dbs_t dbs = ctrl->tofu.dbs;
+
+  if (!dbs)
+    return;  /* Not initialized.  */
+
+  if (dbs->db && dbs->db->type == DB_COMBINED)
+    {
+      log_assert (!dbs->db->next);
+      closedb (dbs->db);
+    }
+  else if (dbs->db)
     {
       struct db *old_head = db_cache;
       struct db *db;
@@ -1103,7 +1119,8 @@ closedbs (struct dbs *dbs)
         }
     }
 
-  xfree (dbs);
+  xfree (ctrl->tofu.dbs);
+  ctrl->tofu.dbs = NULL;
 
 #if DEBUG_TOFU_CACHE
   log_debug ("Queries: %d (prepares saved: %d)\n",
@@ -1142,7 +1159,7 @@ get_single_long_cb2 (void *cookie, int argc, char **argv, char **azColName,
 
    If SHOW_OLD is set, the binding's old policy is displayed.  */
 static gpg_error_t
-record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
+record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
                const char *user_id, enum tofu_policy policy, int show_old)
 {
   char *fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
@@ -1203,7 +1220,7 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
        purposes, there is no need to start a transaction or to die if
        there is a failure.  */
     {
-      rc = sqlite3_stepx
+      rc = gpgsql_stepx
        (db_email->db, &db_email->s.record_binding_get_old_policy,
          get_single_long_cb2, &policy_old, &err,
         "select policy from bindings where fingerprint = ? and email = ?",
@@ -1242,7 +1259,7 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
       goto out;
     }
 
-  rc = sqlite3_stepx
+  rc = gpgsql_stepx
     (db_email->db, &db_email->s.record_binding_update, NULL, NULL, &err,
      "insert or replace into bindings\n"
      " (oid, fingerprint, email, user_id, time, policy)\n"
@@ -1270,7 +1287,7 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
     {
       log_assert (opt.tofu_db_format == TOFU_DB_SPLIT);
 
-      rc = sqlite3_stepx
+      rc = gpgsql_stepx
        (db_key->db, &db_key->s.record_binding_update2, NULL, NULL, &err,
         "insert or replace into bindings\n"
         " (oid, fingerprint, email, user_id)\n"
@@ -1485,7 +1502,7 @@ time_ago_scale (signed long t)
    if CONFLICT is not NULL.  Returns _tofu_GET_POLICY_ERROR if an error
    occurs.  */
 static enum tofu_policy
-get_policy (struct dbs *dbs, const char *fingerprint, const char *email,
+get_policy (tofu_dbs_t dbs, const char *fingerprint, const char *email,
            char **conflict)
 {
   struct db *db;
@@ -1503,7 +1520,7 @@ get_policy (struct dbs *dbs, const char *fingerprint, const char *email,
      (TOFU_POLICY_NONE cannot appear in the DB.  Thus, if POLICY is
      still TOFU_POLICY_NONE after executing the query, then the
      result set was empty.)  */
-  rc = sqlite3_stepx (db->db, &db->s.get_policy_select_policy_and_conflict,
+  rc = gpgsql_stepx (db->db, &db->s.get_policy_select_policy_and_conflict,
                       strings_collect_cb2, &strlist, &err,
                       "select policy, conflict from bindings\n"
                       " where fingerprint = ? and email = ?",
@@ -1585,28 +1602,435 @@ get_policy (struct dbs *dbs, const char *fingerprint, const char *email,
   return policy;
 }
 
-/* Return the trust level (TRUST_NEVER, etc.) for the binding
-   <FINGERPRINT, EMAIL> (email is already normalized).  If no policy
-   is registered, returns TOFU_POLICY_NONE.  If an error occurs,
-   returns _tofu_GET_TRUST_ERROR.
 
-   USER_ID is the unadultered user id.
+/* Format the first part of a conflict message and return that as a
+ * malloced string.  */
+static char *
+format_conflict_msg_part1 (int policy, const char *conflict,
+                           const char *fingerprint, const char *email)
+{
+  estream_t fp;
+  char *binding;
+  int binding_shown = 0;
+  char *tmpstr, *text;
+
+  binding = xasprintf ("<%s, %s>", fingerprint, email);
+
+  fp = es_fopenmem (0, "rw,samethread");
+  if (!fp)
+    log_fatal ("error creating memory stream: %s\n",
+               gpg_strerror (gpg_error_from_syserror()));
+
+  if (policy == TOFU_POLICY_NONE)
+    {
+      es_fprintf (fp, _("The binding %s is NOT known."), binding);
+      es_fputs ("  ", fp);
+      binding_shown = 1;
+    }
+  else if (policy == TOFU_POLICY_ASK
+           /* If there the conflict is with itself, then don't
+            * display this message.  */
+           && conflict && strcmp (conflict, fingerprint))
+    {
+      es_fprintf (fp,
+                  _("The key with fingerprint %s raised a conflict "
+                    "with the binding %s."
+                    "  Since this binding's policy was 'auto', it was "
+                    "changed to 'ask'."),
+                  conflict, binding);
+      es_fputs ("  ", fp);
+      binding_shown = 1;
+    }
+
+  /* TRANSLATORS: The %s%s is replaced by either a fingerprint and a
+     blank or by two empty strings.  */
+  es_fprintf (fp,
+              _("Please indicate whether you believe the binding %s%s"
+                "is legitimate (the key belongs to the stated owner) "
+                "or a forgery (bad)."),
+              binding_shown ? "" : binding,
+              binding_shown ? "" : " ");
+  es_fputc ('\n', fp);
+
+  xfree (binding);
+
+  es_fputc (0, fp);
+  if (es_fclose_snatch (fp, (void **)&tmpstr, NULL))
+    log_fatal ("error snatching memory stream\n");
+  text = format_text (tmpstr, 0, 72, 80);
+  es_free (tmpstr);
+
+  return text;
+}
+
+
+/* Ask the user about the binding.  There are three ways we could end
+ * up here:
+ *
+ *   - This is a new binding and there is a conflict
+ *     (policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0),
+ *
+ *   - This is a new binding and opt.tofu_default_policy is set to
+ *     ask.  (policy == TOFU_POLICY_NONE && opt.tofu_default_policy ==
+ *     TOFU_POLICY_ASK), or,
+ *
+ *   - The policy is ask (the user deferred last time) (policy ==
+ *     TOFU_POLICY_ASK).
+ */
+static void
+ask_about_binding (tofu_dbs_t dbs,
+                   struct db *db,
+                   enum tofu_policy *policy,
+                   int *trust_level,
+                   int bindings_with_this_email_count,
+                   strlist_t bindings_with_this_email,
+                   char *conflict,
+                   const char *fingerprint,
+                   const char *email,
+                   const char *user_id)
+{
+  char *sqerr = NULL;
+  int rc;
+  estream_t fp;
+  strlist_t other_user_ids = NULL;
+  struct signature_stats *stats = NULL;
+  struct signature_stats *stats_iter = NULL;
+  char *prompt;
+  char *choices;
+  struct db *db_key;
+
+  fp = es_fopenmem (0, "rw,samethread");
+  if (!fp)
+    log_fatal ("error creating memory stream: %s\n",
+               gpg_strerror (gpg_error_from_syserror()));
+
+  {
+    char *text = format_conflict_msg_part1 (*policy, conflict,
+                                            fingerprint, email);
+    es_fputs (text, fp);
+    es_fputc ('\n', fp);
+    xfree (text);
+  }
+
+  /* Find other user ids associated with this key and whether the
+   * bindings are marked as good or bad.  */
+  if (opt.tofu_db_format == TOFU_DB_SPLIT)
+    {
+      /* In the split format, we need to search in the fingerprint DB
+       * for all the emails associated with this key, not the email DB.  */
+      db_key = getdb (dbs, fingerprint, DB_KEY);
+    }
+  else
+    db_key = db;
+
+  if (db_key)
+    {
+      rc = gpgsql_stepx
+        (db_key->db, &db_key->s.get_trust_gather_other_user_ids,
+         strings_collect_cb2, &other_user_ids, &sqerr,
+         opt.tofu_db_format == TOFU_DB_SPLIT
+         ? "select user_id, email from bindings where fingerprint = ?;"
+         : "select user_id, policy from bindings where fingerprint = ?;",
+         SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_END);
+      if (rc)
+        {
+          log_error (_("error gathering other user IDs: %s\n"), sqerr);
+          sqlite3_free (sqerr);
+          sqerr = NULL;
+        }
+    }
+
+  if (other_user_ids)
+    {
+      strlist_t strlist_iter;
+
+      es_fprintf (fp, _("Known user IDs associated with this key:\n"));
+      for (strlist_iter = other_user_ids;
+           strlist_iter;
+           strlist_iter = strlist_iter->next)
+        {
+          char *other_user_id = strlist_iter->d;
+          char *other_thing;
+          enum tofu_policy other_policy;
+
+          log_assert (strlist_iter->next);
+          strlist_iter = strlist_iter->next;
+          other_thing = strlist_iter->d;
+
+          if (opt.tofu_db_format == TOFU_DB_SPLIT)
+            other_policy = get_policy (dbs, fingerprint, other_thing, NULL);
+          else
+            other_policy = atoi (other_thing);
+
+          es_fprintf (fp, "  %s (", other_user_id);
+          es_fprintf (fp, _("policy: %s"), tofu_policy_str (other_policy));
+          es_fprintf (fp, ")\n");
+        }
+      es_fprintf (fp, "\n");
+
+      free_strlist (other_user_ids);
+    }
+
+  /* Find other keys associated with this email address.  */
+  /* FIXME: When generating the statistics, do we want the time
+     embedded in the signature (column 'sig_time') or the time that
+     we first verified the signature (column 'time').  */
+  rc = gpgsql_stepx
+    (db->db, &db->s.get_trust_gather_other_keys,
+     signature_stats_collect_cb, &stats, &sqerr,
+     "select fingerprint, policy, time_ago, count(*)\n"
+     " from (select bindings.*,\n"
+     "        case\n"
+     /* From the future (but if its just a couple of hours in the
+      * future don't turn it into a warning)?  Or should we use
+      * small, medium or large units?  (Note: whatever we do, we
+      * keep the value in seconds.  Then when we group, everything
+      * that rounds to the same number of seconds is grouped.)  */
+     "         when delta < -("STRINGIFY (TIME_AGO_FUTURE_IGNORE)") then -1\n"
+     "         when delta < ("STRINGIFY (TIME_AGO_MEDIUM_THRESHOLD)")\n"
+     "          then max(0,\n"
+     "                   round(delta / ("STRINGIFY (TIME_AGO_UNIT_SMALL)"))\n"
+     "               * ("STRINGIFY (TIME_AGO_UNIT_SMALL)"))\n"
+     "         when delta < ("STRINGIFY (TIME_AGO_LARGE_THRESHOLD)")\n"
+     "          then round(delta / ("STRINGIFY (TIME_AGO_UNIT_MEDIUM)"))\n"
+     "               * ("STRINGIFY (TIME_AGO_UNIT_MEDIUM)")\n"
+     "         else round(delta / ("STRINGIFY (TIME_AGO_UNIT_LARGE)"))\n"
+     "              * ("STRINGIFY (TIME_AGO_UNIT_LARGE)")\n"
+     "        end time_ago,\n"
+     "        delta time_ago_raw\n"
+     "       from bindings\n"
+     "       left join\n"
+     "         (select *,\n"
+     "            cast(strftime('%s','now') - sig_time as real) delta\n"
+     "           from signatures) ss\n"
+     "        on ss.binding = bindings.oid)\n"
+     " where email = ?\n"
+     " group by fingerprint, time_ago\n"
+     /* Make sure the current key is first.  */
+     " order by fingerprint = ? asc, fingerprint desc, time_ago desc;\n",
+     SQLITE_ARG_STRING, email, SQLITE_ARG_STRING, fingerprint,
+     SQLITE_ARG_END);
+  if (rc)
+    {
+      strlist_t strlist_iter;
+
+      log_error (_("error gathering signature stats: %s\n"), sqerr);
+      sqlite3_free (sqerr);
+      sqerr = NULL;
 
-   If MAY_ASK is set, then we may interact with the user.  This is
-   necessary if there is a conflict or the binding's policy is
-   TOFU_POLICY_ASK.  In the case of a conflict, we set the new
-   conflicting binding's policy to TOFU_POLICY_ASK.  In either case,
-   we return TRUST_UNDEFINED.  */
+      es_fprintf (fp, ngettext("The email address \"%s\" is"
+                               " associated with %d key:\n",
+                               "The email address \"%s\" is"
+                               " associated with %d keys:\n",
+                               bindings_with_this_email_count),
+                  email, bindings_with_this_email_count);
+      for (strlist_iter = bindings_with_this_email;
+           strlist_iter;
+           strlist_iter = strlist_iter->next)
+        es_fprintf (fp, "  %s\n", strlist_iter->d);
+    }
+  else
+    {
+      char *key = NULL;
+
+      if (! stats || strcmp (stats->fingerprint, fingerprint))
+        {
+          /* If we have already added this key to the DB, then it will
+           * be first (see the above select).  Since the first key on
+           * the list is not this key, we must not yet have verified any
+           * messages signed by this key.  Add a dummy entry.  */
+          signature_stats_prepend (&stats, fingerprint, TOFU_POLICY_AUTO, 0, 0);
+        }
+
+      es_fprintf (fp, _("Statistics for keys with the email address \"%s\":\n"),
+                  email);
+      for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
+        {
+          if (! key || strcmp (key, stats_iter->fingerprint))
+            {
+              int this_key;
+              char *key_pp;
+
+              key = stats_iter->fingerprint;
+              this_key = strcmp (key, fingerprint) == 0;
+              key_pp = format_hexfingerprint (key, NULL, 0);
+              es_fprintf (fp, "  %s (", key_pp);
+              if (this_key)
+                es_fprintf (fp, _("this key"));
+              else
+                es_fprintf (fp, _("policy: %s"),
+                            tofu_policy_str (stats_iter->policy));
+              es_fputs ("):\n", fp);
+              xfree (key_pp);
+            }
+
+          es_fputs ("    ", fp);
+          if (stats_iter->time_ago == -1)
+            es_fprintf (fp, ngettext("%ld message signed in the future.",
+                                     "%ld messages signed in the future.",
+                                     stats_iter->count), stats_iter->count);
+          else
+            {
+              long t_scaled = time_ago_scale (stats_iter->time_ago);
+
+              /* TANSLATORS: This string is concatenated with one of
+               * the day/week/month strings to form one sentence.  */
+              es_fprintf (fp, ngettext("%ld message signed",
+                                       "%ld messages signed",
+                                       stats_iter->count), stats_iter->count);
+              if (!stats_iter->count)
+                es_fputs (".", fp);
+              else if (stats_iter->time_ago < TIME_AGO_UNIT_MEDIUM)
+                es_fprintf (fp, ngettext(" over the past %ld day.",
+                                         " over the past %ld days.",
+                                         t_scaled), t_scaled);
+              else if (stats_iter->time_ago < TIME_AGO_UNIT_LARGE)
+                es_fprintf (fp, ngettext(" over the past %ld week.",
+                                         " over the past %ld weeks.",
+                                         t_scaled), t_scaled);
+              else
+                es_fprintf (fp, ngettext(" over the past %ld month.",
+                                         " over the past %ld months.",
+                                         t_scaled), t_scaled);
+            }
+          es_fputs ("\n", fp);
+        }
+    }
+
+
+  if ((*policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0)
+      || (*policy == TOFU_POLICY_ASK && conflict))
+    {
+      /* This is a conflict.  */
+
+      /* TRANSLATORS: Please translate the text found in the source
+       * file below.  We don't directly internationalize that text so
+       * that we can tweak it without breaking translations.  */
+      char *text = _("TOFU detected a binding conflict");
+      char *textbuf;
+      if (!strcmp (text, "TOFU detected a binding conflict"))
+        {
+          /* No translation.  Use the English text.  */
+          text =
+            "Normally, there is only a single key associated with an email "
+            "address.  However, people sometimes generate a new key if "
+            "their key is too old or they think it might be compromised.  "
+            "Alternatively, a new key may indicate a man-in-the-middle "
+            "attack!  Before accepting this key, you should talk to or "
+            "call the person to make sure this new key is legitimate.";
+        }
+      textbuf = format_text (text, 0, 72, 80);
+      es_fprintf (fp, "\n%s\n", text);
+      xfree (textbuf);
+    }
+
+  es_fputc ('\n', fp);
+
+  /* Add a NUL terminator.  */
+  es_fputc (0, fp);
+  if (es_fclose_snatch (fp, (void **) &prompt, NULL))
+    log_fatal ("error snatching memory stream\n");
+
+  /* I think showing the large message once is sufficient.  If we
+   * would move it right before the cpr_get many lines will scroll
+   * away and the user might not realize that he merely entered a
+   * wrong choise (because he does not see that either).  As a small
+   * benefit we allow C-L to redisplay everything.  */
+  tty_printf ("%s", prompt);
+  while (1)
+    {
+      char *response;
+
+      /* TRANSLATORS: Two letters (normally the lower and upper case
+       * version of the hotkey) for each of the five choices.  If
+       * there is only one choice in your language, repeat it.  */
+      choices = _("gG" "aA" "uU" "rR" "bB");
+      if (strlen (choices) != 10)
+        log_bug ("Bad TOFU conflict translation!  Please report.");
+
+      response = cpr_get
+        ("tofu.conflict",
+         _("(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "));
+      trim_spaces (response);
+      cpr_kill_prompt ();
+      if (*response == CONTROL_L)
+        tty_printf ("%s", prompt);
+      else if (strlen (response) == 1)
+        {
+          char *choice = strchr (choices, *response);
+          if (choice)
+            {
+              int c = ((size_t) choice - (size_t) choices) / 2;
+
+              switch (c)
+                {
+                case 0: /* Good.  */
+                  *policy = TOFU_POLICY_GOOD;
+                  *trust_level = tofu_policy_to_trust_level (*policy);
+                  break;
+                case 1: /* Accept once.  */
+                  *policy = TOFU_POLICY_ASK;
+                  *trust_level = tofu_policy_to_trust_level (TOFU_POLICY_GOOD);
+                  break;
+                case 2: /* Unknown.  */
+                  *policy = TOFU_POLICY_UNKNOWN;
+                  *trust_level = tofu_policy_to_trust_level (*policy);
+                  break;
+                case 3: /* Reject once.  */
+                  *policy = TOFU_POLICY_ASK;
+                  *trust_level = tofu_policy_to_trust_level (TOFU_POLICY_BAD);
+                  break;
+                case 4: /* Bad.  */
+                  *policy = TOFU_POLICY_BAD;
+                  *trust_level = tofu_policy_to_trust_level (*policy);
+                  break;
+                default:
+                  log_bug ("c should be between 0 and 4 but it is %d!", c);
+                }
+
+              if (record_binding (dbs, fingerprint, email, user_id,
+                                  *policy, 0))
+                {
+                  /* If there's an error registering the
+                   * binding, don't save the signature.  */
+                  *trust_level = _tofu_GET_TRUST_ERROR;
+                }
+              break;
+            }
+        }
+      xfree (response);
+    }
+
+  xfree (prompt);
+
+  signature_stats_free (stats);
+}
+
+
+/* Return the trust level (TRUST_NEVER, etc.) for the binding
+ * <FINGERPRINT, EMAIL> (email is already normalized).  If no policy
+ * is registered, returns TOFU_POLICY_NONE.  If an error occurs,
+ * returns _tofu_GET_TRUST_ERROR.
+ *
+ * PK is the public key object for FINGERPRINT.
+ *
+ * USER_ID is the unadulterated user id.
+ *
+ * If MAY_ASK is set, then we may interact with the user.  This is
+ * necessary if there is a conflict or the binding's policy is
+ * TOFU_POLICY_ASK.  In the case of a conflict, we set the new
+ * conflicting binding's policy to TOFU_POLICY_ASK.  In either case,
+ * we return TRUST_UNDEFINED.  */
 static enum tofu_policy
-get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
+get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
+           const char *fingerprint, const char *email,
           const char *user_id, int may_ask)
 {
-  char *fingerprint_pp;
   struct db *db;
   enum tofu_policy policy;
   char *conflict = NULL;
   int rc;
-  char *err = NULL;
+  char *sqerr = NULL;
   strlist_t bindings_with_this_email = NULL;
   int bindings_with_this_email_count;
   int change_conflicting_to_ask = 0;
@@ -1629,46 +2053,12 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
   if (! db)
     return _tofu_GET_TRUST_ERROR;
 
-  fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
-
   policy = get_policy (dbs, fingerprint, email, &conflict);
   if (policy == TOFU_POLICY_AUTO || policy == TOFU_POLICY_NONE)
-    /* See if the key is ultimately trusted.  If so, we're done.  */
-    {
-      PKT_public_key *pk;
+    { /* See if the key is ultimately trusted.  If so, we're done.  */
       u32 kid[2];
-      char fpr_bin[MAX_FINGERPRINT_LEN+1];
-      size_t fpr_bin_len;
 
-      if (!hex2str (fingerprint, fpr_bin, sizeof fpr_bin, &fpr_bin_len))
-        {
-          log_error ("error converting fingerprint: %s\n",
-                     gpg_strerror (gpg_error_from_syserror ()));
-          return _tofu_GET_TRUST_ERROR;
-        }
-
-      /* We need to lookup the key by fingerprint again so that we can
-         properly extract the keyid.  Extracting direct from the
-         fingerprint works only for v4 keys and would assume that
-         there is no collision in the low 64 bit.  We can't guarantee
-         the latter in case the Tofu DB is used with a different
-         keyring.  In any case the UTK stuff needs to be changed to
-         use only fingerprints.  */
-      pk = xtrycalloc (1, sizeof *pk);
-      if (!pk)
-         {
-           log_error (_("out of core\n"));
-           return _tofu_GET_TRUST_ERROR;
-         }
-      rc = get_pubkey_byfprint_fast (pk, fpr_bin, fpr_bin_len);
-      if (rc)
-        {
-          log_error (_("public key %s not found: %s\n"),
-                     fingerprint, gpg_strerror (rc));
-          return _tofu_GET_TRUST_ERROR;
-        }
       keyid_from_pk (pk, kid);
-      free_public_key (pk);
 
       if (tdb_keyid_is_utk (kid))
         {
@@ -1704,7 +2094,7 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
     case TOFU_POLICY_UNKNOWN:
     case TOFU_POLICY_BAD:
       /* The saved judgement is auto -> auto, good, unknown or bad.
-        We don't need to ask the user anything.  */
+       * We don't need to ask the user anything.  */
       if (DBG_TRUST)
        log_debug ("TOFU: Known binding <%s, %s>'s policy: %s\n",
                   fingerprint, email, tofu_policy_str (policy));
@@ -1723,7 +2113,7 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
 
     case TOFU_POLICY_NONE:
       /* The binding is new, we need to check for conflicts.  Case #3
-        below.  */
+       * below.  */
       break;
 
     case _tofu_GET_POLICY_ERROR:
@@ -1736,49 +2126,51 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
 
 
   /* We get here if:
-
-       1. The saved policy is auto and the default policy is ask
-          (get_policy() == TOFU_POLICY_AUTO
-           && opt.tofu_default_policy == TOFU_POLICY_ASK)
-
-       2. The saved policy is ask (either last time the user selected
-          accept once or reject once or there was a conflict and this
-          binding's policy was changed from auto to ask)
-         (policy == TOFU_POLICY_ASK), or,
-
-       3. We don't have a saved policy (policy == TOFU_POLICY_NONE)
-          (need to check for a conflict).
+   *
+   *   1. The saved policy is auto and the default policy is ask
+   *      (get_policy() == TOFU_POLICY_AUTO
+   *       && opt.tofu_default_policy == TOFU_POLICY_ASK)
+   *
+   *   2. The saved policy is ask (either last time the user selected
+   *      accept once or reject once or there was a conflict and this
+   *      binding's policy was changed from auto to ask)
+   *      (policy == TOFU_POLICY_ASK), or,
+   *
+   *   3. We don't have a saved policy (policy == TOFU_POLICY_NONE)
+   *      (need to check for a conflict).
    */
 
   /* Look for conflicts.  This is needed in all 3 cases.
-
-     Get the fingerprints of any bindings that share the email
-     address.  Note: if the binding in question is in the DB, it will
-     also be returned.  Thus, if the result set is empty, then this is
-     a new binding.  */
-  rc = sqlite3_stepx
+   *
+   * Get the fingerprints of any bindings that share the email
+   * address.  Note: if the binding in question is in the DB, it will
+   * also be returned.  Thus, if the result set is empty, then this is
+   * a new binding.  */
+  rc = gpgsql_stepx
     (db->db, &db->s.get_trust_bindings_with_this_email,
-     strings_collect_cb2, &bindings_with_this_email, &err,
+     strings_collect_cb2, &bindings_with_this_email, &sqerr,
      "select distinct fingerprint from bindings where email = ?;",
      SQLITE_ARG_STRING, email, SQLITE_ARG_END);
   if (rc)
     {
-      log_error (_("error reading TOFU database: %s\n"), err);
+      log_error (_("error reading TOFU database: %s\n"), sqerr);
       print_further_info ("listing fingerprints");
-      sqlite3_free (err);
+      sqlite3_free (sqerr);
       goto out;
     }
 
   bindings_with_this_email_count = strlist_length (bindings_with_this_email);
   if (bindings_with_this_email_count == 0
       && opt.tofu_default_policy != TOFU_POLICY_ASK)
-    /* New binding with no conflict and a concrete default policy.
-
-       We've never observed a binding with this email address
-       (BINDINGS_WITH_THIS_EMAIL_COUNT is 0 and the above query would return
-       the current binding if it were in the DB) and we have a default
-       policy, which is not to ask the user.  */
     {
+      /* New binding with no conflict and a concrete default policy.
+       *
+       * We've never observed a binding with this email address
+       * BINDINGS_WITH_THIS_EMAIL_COUNT is 0 and the above query would
+       * return the current binding if it were in the DB) and we have
+       * a default policy, which is not to ask the user.
+       */
+
       /* If we've seen this binding, then we've seen this email and
         policy couldn't possibly be TOFU_POLICY_NONE.  */
       log_assert (policy == TOFU_POLICY_NONE);
@@ -1801,18 +2193,20 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
     }
 
   if (policy == TOFU_POLICY_NONE)
-    /* This is a new binding and we have a conflict.  Mark any
-       conflicting bindings that have an automatic policy as now
-       requiring confirmation.  Note: we delay this until after we ask
-       for confirmation so that when the current policy is printed, it
-       is correct.  */
-    change_conflicting_to_ask = 1;
+    {
+      /* This is a new binding and we have a conflict.  Mark any
+       * conflicting bindings that have an automatic policy as now
+       * requiring confirmation.  Note: we delay this until after we
+       * ask for confirmation so that when the current policy is
+       * printed, it is correct.  */
+      change_conflicting_to_ask = 1;
+    }
 
   if (! may_ask)
-    /* We can only get here in the third case (no saved policy) and if
-       there is a conflict.  (If the policy was ask (cases #1 and #2)
-       and we weren't allowed to ask, we'd have already exited).  */
     {
+      /* We can only get here in the third case (no saved policy) and
+       * if there is a conflict.  (If the policy was ask (cases #1 and
+       * #2) and we weren't allowed to ask, we'd have already exited).  */
       log_assert (policy == TOFU_POLICY_NONE);
 
       if (record_binding (dbs, fingerprint, email, user_id,
@@ -1824,412 +2218,52 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
       goto out;
     }
 
-  /* If we get here, we need to ask the user about the binding.  There
-     are three ways we could end up here:
-
-       - This is a new binding and there is a conflict
-         (policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0),
-
-       - This is a new binding and opt.tofu_default_policy is set to
-         ask.  (policy == TOFU_POLICY_NONE && opt.tofu_default_policy ==
-         TOFU_POLICY_ASK), or,
-
-       - The policy is ask (the user deferred last time) (policy ==
-         TOFU_POLICY_ASK).
-   */
-  {
-    int is_conflict =
-      ((policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0)
-       || (policy == TOFU_POLICY_ASK && conflict));
-    estream_t fp;
-    strlist_t other_user_ids = NULL;
-    struct signature_stats *stats = NULL;
-    struct signature_stats *stats_iter = NULL;
-    char *prompt;
-    char *choices;
-
-    fp = es_fopenmem (0, "rw,samethread");
-    if (! fp)
-      log_fatal ("error creating memory stream: %s\n",
-                 gpg_strerror (gpg_error_from_syserror()));
-
-    /* Format the first part of the message.  */
-    {
-      estream_t fp1;
-      char *binding = xasprintf ("<%s, %s>", fingerprint, email);
-      int binding_shown = 0;
-      char *tmpstr, *text;
-
-      fp1 = es_fopenmem (0, "rw,samethread");
-      if (!fp1)
-        log_fatal ("error creating memory stream: %s\n",
-                   gpg_strerror (gpg_error_from_syserror()));
-
-      if (policy == TOFU_POLICY_NONE)
-        {
-          es_fprintf (fp1, _("The binding %s is NOT known."), binding);
-          es_fputs ("  ", fp1);
-          binding_shown = 1;
-        }
-      else if (policy == TOFU_POLICY_ASK
-               /* If there the conflict is with itself, then don't
-                  display this message.  */
-               && conflict && strcmp (conflict, fingerprint) != 0)
-        {
-          es_fprintf (fp1,
-                      _("The key with fingerprint %s raised a conflict "
-                        "with the binding %s."
-                        "  Since this binding's policy was 'auto', it was "
-                        "changed to 'ask'."),
-                      conflict, binding);
-          es_fputs ("  ", fp1);
-          binding_shown = 1;
-        }
-
-      /* TRANSLATORS: The %s%s is replaced by either a fingerprint and a
-         blank or by two empty strings.  */
-      es_fprintf (fp1,
-                  _("Please indicate whether you believe the binding %s%s"
-                    "is legitimate (the key belongs to the stated owner) "
-                    "or a forgery (bad)."),
-                  binding_shown ? "" : binding,
-                  binding_shown ? "" : " ");
-      es_fputc ('\n', fp1);
-
-      xfree (binding);
-
-      es_fputc (0, fp1);
-      if (es_fclose_snatch (fp1, (void **)&tmpstr, NULL))
-        log_fatal ("error snatching memory stream\n");
-      text = format_text (tmpstr, 0, 72, 80);
-      es_free (tmpstr);
-
-      es_fputs (text, fp);
-      xfree (text);
-    }
-
-    es_fputc ('\n', fp);
-
-    /* Find other user ids associated with this key and whether the
-       bindings are marked as good or bad.  */
-    {
-      struct db *db_key;
-
-      if (opt.tofu_db_format == TOFU_DB_SPLIT)
-       /* In the split format, we need to search in the fingerprint
-          DB for all the emails associated with this key, not the
-          email DB.  */
-       db_key = getdb (dbs, fingerprint, DB_KEY);
-      else
-       db_key = db;
-
-      if (db_key)
-       {
-         rc = sqlite3_stepx
-           (db_key->db, &db_key->s.get_trust_gather_other_user_ids,
-             strings_collect_cb2, &other_user_ids, &err,
-             opt.tofu_db_format == TOFU_DB_SPLIT
-            ? "select user_id, email from bindings where fingerprint = ?;"
-            : "select user_id, policy from bindings where fingerprint = ?;",
-            SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_END);
-         if (rc)
-           {
-             log_error (_("error gathering other user IDs: %s\n"), err);
-             sqlite3_free (err);
-             err = NULL;
-           }
-       }
-    }
-
-    if (other_user_ids)
-      {
-       strlist_t strlist_iter;
-
-       es_fprintf (fp, _("Known user IDs associated with this key:\n"));
-       for (strlist_iter = other_user_ids;
-            strlist_iter;
-            strlist_iter = strlist_iter->next)
-         {
-           char *other_user_id = strlist_iter->d;
-           char *other_thing;
-           enum tofu_policy other_policy;
-
-           log_assert (strlist_iter->next);
-           strlist_iter = strlist_iter->next;
-           other_thing = strlist_iter->d;
-
-           if (opt.tofu_db_format == TOFU_DB_SPLIT)
-             other_policy = get_policy (dbs, fingerprint, other_thing, NULL);
-           else
-             other_policy = atoi (other_thing);
-
-           es_fprintf (fp, "  %s (", other_user_id);
-           es_fprintf (fp, _("policy: %s"), tofu_policy_str (other_policy));
-           es_fprintf (fp, ")\n");
-          }
-       es_fprintf (fp, "\n");
-
-       free_strlist (other_user_ids);
-      }
-
-    /* Find other keys associated with this email address.  */
-    /* XXX: When generating the statistics, do we want the time
-       embedded in the signature (column 'sig_time') or the time that
-       we first verified the signature (column 'time').  */
-    rc = sqlite3_stepx
-      (db->db, &db->s.get_trust_gather_other_keys,
-       signature_stats_collect_cb, &stats, &err,
-       "select fingerprint, policy, time_ago, count(*)\n"
-       " from (select bindings.*,\n"
-       "        case\n"
-       /* From the future (but if its just a couple of hours in the
-         future don't turn it into a warning)?  Or should we use
-         small, medium or large units?  (Note: whatever we do, we
-         keep the value in seconds.  Then when we group, everything
-         that rounds to the same number of seconds is grouped.)  */
-       "         when delta < -("STRINGIFY (TIME_AGO_FUTURE_IGNORE)") then -1\n"
-       "         when delta < ("STRINGIFY (TIME_AGO_MEDIUM_THRESHOLD)")\n"
-       "          then max(0,\n"
-       "                   round(delta / ("STRINGIFY (TIME_AGO_UNIT_SMALL)"))\n"
-       "               * ("STRINGIFY (TIME_AGO_UNIT_SMALL)"))\n"
-       "         when delta < ("STRINGIFY (TIME_AGO_LARGE_THRESHOLD)")\n"
-       "          then round(delta / ("STRINGIFY (TIME_AGO_UNIT_MEDIUM)"))\n"
-       "               * ("STRINGIFY (TIME_AGO_UNIT_MEDIUM)")\n"
-       "         else round(delta / ("STRINGIFY (TIME_AGO_UNIT_LARGE)"))\n"
-       "              * ("STRINGIFY (TIME_AGO_UNIT_LARGE)")\n"
-       "        end time_ago,\n"
-       "        delta time_ago_raw\n"
-       "       from bindings\n"
-       "       left join\n"
-       "         (select *,\n"
-       "            cast(strftime('%s','now') - sig_time as real) delta\n"
-       "           from signatures) ss\n"
-       "        on ss.binding = bindings.oid)\n"
-       " where email = ?\n"
-       " group by fingerprint, time_ago\n"
-       /* Make sure the current key is first.  */
-       " order by fingerprint = ? asc, fingerprint desc, time_ago desc;\n",
-       SQLITE_ARG_STRING, email, SQLITE_ARG_STRING, fingerprint,
-       SQLITE_ARG_END);
-    if (rc)
-      {
-       strlist_t strlist_iter;
-
-       log_error (_("error gathering signature stats: %s\n"), err);
-       sqlite3_free (err);
-       err = NULL;
-
-       es_fprintf (fp, ngettext("The email address \"%s\" is"
-                                 " associated with %d key:\n",
-                                 "The email address \"%s\" is"
-                                 " associated with %d keys:\n",
-                                 bindings_with_this_email_count),
-                    email, bindings_with_this_email_count);
-       for (strlist_iter = bindings_with_this_email;
-            strlist_iter;
-            strlist_iter = strlist_iter->next)
-         es_fprintf (fp, "  %s\n", strlist_iter->d);
-      }
-    else
-      {
-       char *key = NULL;
-
-       if (! stats || strcmp (stats->fingerprint, fingerprint) != 0)
-         /* If we have already added this key to the DB, then it will
-            be first (see the above select).  Since the first key on
-            the list is not this key, we must not yet have verified
-            any messages signed by this key.  Add a dummy entry.  */
-         signature_stats_prepend (&stats, fingerprint, TOFU_POLICY_AUTO, 0, 0);
-
-       es_fprintf
-          (fp, _("Statistics for keys with the email address \"%s\":\n"),
-           email);
-       for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
-         {
-           if (! key || strcmp (key, stats_iter->fingerprint) != 0)
-             {
-               int this_key;
-                char *key_pp;
-               key = stats_iter->fingerprint;
-               this_key = strcmp (key, fingerprint) == 0;
-                key_pp = format_hexfingerprint (key, NULL, 0);
-                es_fprintf (fp, "  %s (", key_pp);
-               if (this_key)
-                 es_fprintf (fp, _("this key"));
-               else
-                 es_fprintf (fp, _("policy: %s"),
-                             tofu_policy_str (stats_iter->policy));
-                es_fputs ("):\n", fp);
-                xfree (key_pp);
-             }
-
-            es_fputs ("    ", fp);
-           if (stats_iter->time_ago == -1)
-             es_fprintf (fp, ngettext("%ld message signed in the future.",
-                                       "%ld messages signed in the future.",
-                                       stats_iter->count), stats_iter->count);
-           else
-              {
-                long t_scaled = time_ago_scale (stats_iter->time_ago);
-
-                /* TANSLATORS: This string is concatenated with one of
-                 * the day/week/month strings to form one sentence.  */
-                es_fprintf (fp, ngettext("%ld message signed",
-                                         "%ld messages signed",
-                                         stats_iter->count), stats_iter->count);
-                if (!stats_iter->count)
-                  es_fputs (".", fp);
-                else if (stats_iter->time_ago < TIME_AGO_UNIT_MEDIUM)
-                  es_fprintf (fp, ngettext(" over the past %ld day.",
-                                           " over the past %ld days.",
-                                           t_scaled), t_scaled);
-                else if (stats_iter->time_ago < TIME_AGO_UNIT_LARGE)
-                  es_fprintf (fp, ngettext(" over the past %ld week.",
-                                           " over the past %ld weeks.",
-                                           t_scaled), t_scaled);
-                else
-                  es_fprintf (fp, ngettext(" over the past %ld month.",
-                                           " over the past %ld months.",
-                                           t_scaled), t_scaled);
-              }
-            es_fputs ("\n", fp);
-         }
-      }
-
-    if (is_conflict)
-      {
-       /* TRANSLATORS: Please translate the text found in the source
-          file below.  We don't directly internationalize that text
-          so that we can tweak it without breaking translations.  */
-       const char *text = _("TOFU detected a binding conflict");
-        char *textbuf;
-       if (strcmp (text, "TOFU detected a binding conflict") == 0)
-         /* No translation.  Use the English text.  */
-         text =
-           "Normally, there is only a single key associated with an email "
-           "address.  However, people sometimes generate a new key if "
-           "their key is too old or they think it might be compromised.  "
-           "Alternatively, a new key may indicate a man-in-the-middle "
-           "attack!  Before accepting this key, you should talk to or "
-           "call the person to make sure this new key is legitimate.";
-        textbuf = format_text (text, 0, 72, 80);
-       es_fprintf (fp, "\n%s\n", text);
-        xfree (textbuf);
-      }
-
-    es_fputc ('\n', fp);
-
-    /* Add a NUL terminator.  */
-    es_fputc (0, fp);
-    if (es_fclose_snatch (fp, (void **) &prompt, NULL))
-      log_fatal ("error snatching memory stream\n");
-
-    /* I think showing the large message once is sufficient.  If we
-       would move it right before the cpr_get many lines will scroll
-       away and the user might not realize that he merely entered a
-       wrong choise (because he does not see that either).  As a small
-       benefit we allow C-L to redisplay everything.  */
-    tty_printf ("%s", prompt);
-    while (1)
-      {
-       char *response;
-
-        /* TRANSLATORS: Two letters (normally the lower and upper case
-           version of the hotkey) for each of the five choices.  If
-           there is only one choice in your language, repeat it.  */
-        choices = _("gG" "aA" "uU" "rR" "bB");
-       if (strlen (choices) != 10)
-         log_bug ("Bad TOFU conflict translation!  Please report.");
-
-       response = cpr_get
-          ("tofu.conflict",
-           _("(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "));
-       trim_spaces (response);
-       cpr_kill_prompt ();
-        if (*response == CONTROL_L)
-          tty_printf ("%s", prompt);
-       else if (strlen (response) == 1)
-         {
-           char *choice = strchr (choices, *response);
-           if (choice)
-             {
-               int c = ((size_t) choice - (size_t) choices) / 2;
-
-               switch (c)
-                 {
-                 case 0: /* Good.  */
-                   policy = TOFU_POLICY_GOOD;
-                   trust_level = tofu_policy_to_trust_level (policy);
-                   break;
-                 case 1: /* Accept once.  */
-                   policy = TOFU_POLICY_ASK;
-                   trust_level =
-                     tofu_policy_to_trust_level (TOFU_POLICY_GOOD);
-                   break;
-                 case 2: /* Unknown.  */
-                   policy = TOFU_POLICY_UNKNOWN;
-                   trust_level = tofu_policy_to_trust_level (policy);
-                   break;
-                 case 3: /* Reject once.  */
-                   policy = TOFU_POLICY_ASK;
-                   trust_level =
-                     tofu_policy_to_trust_level (TOFU_POLICY_BAD);
-                   break;
-                 case 4: /* Bad.  */
-                   policy = TOFU_POLICY_BAD;
-                   trust_level = tofu_policy_to_trust_level (policy);
-                   break;
-                 default:
-                   log_bug ("c should be between 0 and 4 but it is %d!", c);
-                 }
-
-               if (record_binding (dbs, fingerprint, email, user_id,
-                                   policy, 0) != 0)
-                 /* If there's an error registering the
-                    binding, don't save the signature.  */
-                 trust_level = _tofu_GET_TRUST_ERROR;
-
-               break;
-             }
-         }
-       xfree (response);
-      }
-
-    xfree (prompt);
-
-    signature_stats_free (stats);
-  }
+  /* If we get here, we need to ask the user about the binding.  */
+  ask_about_binding (dbs, db,
+                     &policy,
+                     &trust_level,
+                     bindings_with_this_email_count,
+                     bindings_with_this_email,
+                     conflict,
+                     fingerprint,
+                     email,
+                     user_id);
 
  out:
   if (change_conflicting_to_ask)
     {
       if (! may_ask)
-       /* If we weren't allowed to ask, also update this key as
-          conflicting with itself.  */
-       rc = sqlite3_exec_printf
-         (db->db, NULL, NULL, &err,
-          "update bindings set policy = %d, conflict = %Q"
-          " where email = %Q"
-          "  and (policy = %d or (policy = %d and fingerprint = %Q));",
-          TOFU_POLICY_ASK, fingerprint, email, TOFU_POLICY_AUTO,
-          TOFU_POLICY_ASK, fingerprint);
+        {
+          /* If we weren't allowed to ask, also update this key as
+             conflicting with itself.  */
+          rc = gpgsql_exec_printf
+            (db->db, NULL, NULL, &sqerr,
+             "update bindings set policy = %d, conflict = %Q"
+             " where email = %Q"
+             "  and (policy = %d or (policy = %d and fingerprint = %Q));",
+             TOFU_POLICY_ASK, fingerprint, email, TOFU_POLICY_AUTO,
+             TOFU_POLICY_ASK, fingerprint);
+        }
       else
-       rc = sqlite3_exec_printf
-         (db->db, NULL, NULL, &err,
-          "update bindings set policy = %d, conflict = %Q"
-          " where email = %Q and fingerprint != %Q and policy = %d;",
-          TOFU_POLICY_ASK, fingerprint, email, fingerprint, TOFU_POLICY_AUTO);
+        {
+          rc = gpgsql_exec_printf
+            (db->db, NULL, NULL, &sqerr,
+             "update bindings set policy = %d, conflict = %Q"
+             " where email = %Q and fingerprint != %Q and policy = %d;",
+             TOFU_POLICY_ASK, fingerprint, email, fingerprint,
+             TOFU_POLICY_AUTO);
+        }
+
       if (rc)
        {
-         log_error (_("error changing TOFU policy: %s\n"), err);
-         sqlite3_free (err);
-         goto out;
+         log_error (_("error changing TOFU policy: %s\n"), sqerr);
+         sqlite3_free (sqerr);
+          sqerr = NULL;
        }
     }
 
   xfree (conflict);
   free_strlist (bindings_with_this_email);
-  xfree (fingerprint_pp);
 
   return trust_level;
 }
@@ -2405,7 +2439,7 @@ write_stats_status (long messages, enum tofu_policy policy,
 }
 
 static void
-show_statistics (struct dbs *dbs, const char *fingerprint,
+show_statistics (tofu_dbs_t dbs, const char *fingerprint,
                 const char *email, const char *user_id,
                 const char *sig_exclude)
 {
@@ -2421,7 +2455,7 @@ show_statistics (struct dbs *dbs, const char *fingerprint,
 
   fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
 
-  rc = sqlite3_exec_printf
+  rc = gpgsql_exec_printf
     (db->db, strings_collect_cb, &strlist, &err,
      "select count (*), strftime('%%s','now') - min (signatures.time),\n"
      "  strftime('%%s','now') - max (signatures.time)\n"
@@ -2542,15 +2576,18 @@ show_statistics (struct dbs *dbs, const char *fingerprint,
               log_fatal ("error snatching memory stream\n");
             msg = format_text (tmpmsg, 0, 72, 80);
             es_free (tmpmsg);
-            for (p=msg; *p; p++)
-              if (*p == '~')
-                *p = ' ';
 
             /* Print a status line but suppress the trailing LF.
              * Spaces are not percent escaped. */
             if (*msg)
               write_status_buffer (STATUS_TOFU_STATS_LONG,
                                    msg, strlen (msg)-1, -1);
+
+            /* Remove the non-breaking space markers.  */
+            for (p=msg; *p; p++)
+              if (*p == '~')
+                *p = ' ';
+
           }
 
          log_string (GPGRT_LOG_INFO, msg);
@@ -2643,14 +2680,13 @@ email_from_user_id (const char *user_id)
    This function returns the binding's trust level on return.  If an
    error occurs, this function returns TRUST_UNKNOWN.  */
 int
-tofu_register (PKT_public_key *pk, const char *user_id,
+tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
               const byte *sig_digest_bin, int sig_digest_bin_len,
               time_t sig_time, const char *origin, int may_ask)
 {
-  struct dbs *dbs;
+  tofu_dbs_t dbs;
   struct db *db;
   char *fingerprint = NULL;
-  char *fingerprint_pp = NULL;
   char *email = NULL;
   char *err = NULL;
   int rc;
@@ -2661,7 +2697,7 @@ tofu_register (PKT_public_key *pk, const char *user_id,
 
   sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len);
 
-  dbs = opendbs ();
+  dbs = opendbs (ctrl);
   if (! dbs)
     {
       log_error (_("error opening TOFU database: %s\n"),
@@ -2670,7 +2706,6 @@ tofu_register (PKT_public_key *pk, const char *user_id,
     }
 
   fingerprint = hexfingerprint (pk, NULL, 0);
-  fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
 
   if (! *user_id)
     {
@@ -2686,7 +2721,7 @@ tofu_register (PKT_public_key *pk, const char *user_id,
 
   /* It's necessary to get the trust so that we are certain that the
      binding has been registered.  */
-  trust_level = get_trust (dbs, fingerprint, email, user_id, may_ask);
+  trust_level = get_trust (dbs, pk, fingerprint, email, user_id, may_ask);
   if (trust_level == _tofu_GET_TRUST_ERROR)
     /* An error.  */
     {
@@ -2711,7 +2746,7 @@ tofu_register (PKT_public_key *pk, const char *user_id,
 
   /* If we've already seen this signature before, then don't add
      it again.  */
-  rc = sqlite3_stepx
+  rc = gpgsql_stepx
     (db->db, &db->s.register_already_seen,
      get_single_unsigned_long_cb2, &c, &err,
      "select count (*)\n"
@@ -2761,7 +2796,7 @@ tofu_register (PKT_public_key *pk, const char *user_id,
 
       log_assert (c == 0);
 
-      rc = sqlite3_stepx
+      rc = gpgsql_stepx
        (db->db, &db->s.register_insert, NULL, NULL, &err,
         "insert into signatures\n"
         " (binding, sig_digest, origin, sig_time, time)\n"
@@ -2801,10 +2836,7 @@ tofu_register (PKT_public_key *pk, const char *user_id,
                     already_verified ? NULL : sig_digest);
 
   xfree (email);
-  xfree (fingerprint_pp);
   xfree (fingerprint);
-  if (dbs)
-    closedbs (dbs);
   xfree (sig_digest);
 
   return trust_level;
@@ -2884,15 +2916,15 @@ tofu_wot_trust_combine (int tofu_base, int wot_base)
 
    Returns TRUST_UNDEFINED if an error occurs.  */
 int
-tofu_get_validity (PKT_public_key *pk, const char *user_id,
+tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
                   int may_ask)
 {
-  struct dbs *dbs;
+  tofu_dbs_t dbs;
   char *fingerprint = NULL;
   char *email = NULL;
   int trust_level = TRUST_UNDEFINED;
 
-  dbs = opendbs ();
+  dbs = opendbs (ctrl);
   if (! dbs)
     {
       log_error (_("error opening TOFU database: %s\n"),
@@ -2911,7 +2943,7 @@ tofu_get_validity (PKT_public_key *pk, const char *user_id,
 
   email = email_from_user_id (user_id);
 
-  trust_level = get_trust (dbs, fingerprint, email, user_id, may_ask);
+  trust_level = get_trust (dbs, pk, fingerprint, email, user_id, may_ask);
   if (trust_level == _tofu_GET_TRUST_ERROR)
     /* An error.  */
     trust_level = TRUST_UNDEFINED;
@@ -2922,9 +2954,6 @@ tofu_get_validity (PKT_public_key *pk, const char *user_id,
  die:
   xfree (email);
   xfree (fingerprint);
-  if (dbs)
-    closedbs (dbs);
-
   return trust_level;
 }
 
@@ -2936,16 +2965,16 @@ tofu_get_validity (PKT_public_key *pk, const char *user_id,
 
    Returns 0 on success and an error code otherwise.  */
 gpg_error_t
-tofu_set_policy (kbnode_t kb, enum tofu_policy policy)
+tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy)
 {
-  struct dbs *dbs;
+  tofu_dbs_t dbs;
   PKT_public_key *pk;
   char *fingerprint = NULL;
 
   log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
   pk = kb->pkt->pkt.public_key;
 
-  dbs = opendbs ();
+  dbs = opendbs (ctrl);
   if (! dbs)
     {
       log_error (_("error opening TOFU database: %s\n"),
@@ -2984,8 +3013,6 @@ tofu_set_policy (kbnode_t kb, enum tofu_policy policy)
     }
 
   xfree (fingerprint);
-  closedbs (dbs);
-
   return 0;
 }
 
@@ -2997,13 +3024,13 @@ tofu_set_policy (kbnode_t kb, enum tofu_policy policy)
 
    Returns 0 on success and an error code otherwise.  */
 gpg_error_t
-tofu_set_policy_by_keyid (u32 *keyid, enum tofu_policy policy)
+tofu_set_policy_by_keyid (ctrl_t ctrl, u32 *keyid, enum tofu_policy policy)
 {
   kbnode_t keyblock = get_pubkeyblock (keyid);
   if (! keyblock)
     return gpg_error (GPG_ERR_NO_PUBKEY);
 
-  return tofu_set_policy (keyblock, policy);
+  return tofu_set_policy (ctrl, keyblock, policy);
 }
 
 /* Return the TOFU policy for the specified binding in *POLICY.  If no
@@ -3014,10 +3041,10 @@ tofu_set_policy_by_keyid (u32 *keyid, enum tofu_policy policy)
 
    Returns 0 on success and an error code otherwise.  */
 gpg_error_t
-tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id,
                 enum tofu_policy *policy)
 {
-  struct dbs *dbs;
+  tofu_dbs_t dbs;
   char *fingerprint;
   char *email;
 
@@ -3025,7 +3052,7 @@ tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
   log_assert (pk->main_keyid[0] == pk->keyid[0]
               && pk->main_keyid[1] == pk->keyid[1]);
 
-  dbs = opendbs ();
+  dbs = opendbs (ctrl);
   if (! dbs)
     {
       log_error (_("error opening TOFU database: %s\n"),
@@ -3041,8 +3068,6 @@ tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
 
   xfree (email);
   xfree (fingerprint);
-  closedbs (dbs);
-
   if (*policy == _tofu_GET_POLICY_ERROR)
     return gpg_error (GPG_ERR_GENERAL);
   return 0;
index 7ee1083..d3448b9 100644 (file)
@@ -63,6 +63,7 @@ enum tofu_policy
     _tofu_GET_POLICY_ERROR = 100
   };
 
+
 /* Return a string representation of a trust policy.  Returns "???" if
    POLICY is not valid.  */
 const char *tofu_policy_str (enum tofu_policy policy);
@@ -78,7 +79,7 @@ int tofu_policy_to_trust_level (enum tofu_policy policy);
    interact with the user in the case of a conflict or if the
    binding's policy is ask.  This function returns the binding's trust
    level.  If an error occurs, it returns TRUST_UNKNOWN.  */
-int tofu_register (PKT_public_key *pk, const char *user_id,
+int tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
                   const byte *sigs_digest, int sigs_digest_len,
                   time_t sig_time, const char *origin, int may_ask);
 
@@ -91,18 +92,21 @@ int tofu_wot_trust_combine (int tofu, int wot);
    <PK, USER_ID>.  If MAY_ASK is 1, then this function may
    interact with the user.  If not, TRUST_UNKNOWN is returned.  If an
    error occurs, TRUST_UNDEFINED is returned.  */
-int tofu_get_validity (PKT_public_key *pk, const char *user_id, int may_ask);
+int tofu_get_validity (ctrl_t ctrl,
+                       PKT_public_key *pk, const char *user_id, int may_ask);
 
 /* Set the policy for all non-revoked user ids in the keyblock KB to
    POLICY.  */
-gpg_error_t tofu_set_policy (kbnode_t kb, enum tofu_policy policy);
+gpg_error_t tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy);
 
 /* Set the TOFU policy for all non-revoked users in the key with the
    key id KEYID to POLICY.  */
-gpg_error_t tofu_set_policy_by_keyid (u32 *keyid, enum tofu_policy policy);
+gpg_error_t tofu_set_policy_by_keyid (ctrl_t ctrl,
+                                      u32 *keyid, enum tofu_policy policy);
 
 /* Return the TOFU policy for the specified binding in *POLICY.  */
-gpg_error_t tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+gpg_error_t tofu_get_policy (ctrl_t ctrl,
+                             PKT_public_key *pk, PKT_user_id *user_id,
                             enum tofu_policy *policy);
 
 /* When doing a lot of DB activities (in particular, when listing
@@ -111,4 +115,7 @@ gpg_error_t tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
 void tofu_begin_batch_update (void);
 void tofu_end_batch_update (void);
 
+/* Release all of the resources associated with a DB meta-handle.  */
+void tofu_closedbs (ctrl_t ctrl);
+
 #endif /*G10_TOFU_H*/
index 82de7cb..8790754 100644 (file)
@@ -131,7 +131,7 @@ string_to_trust_value (const char *str)
 
 
 const char *
-uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid)
+uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid)
 {
   if (!key && !uid)
     {
@@ -151,11 +151,12 @@ uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid)
     return                         _("[ expired]");
   else if(key)
     {
-      switch (get_validity (key, uid, NULL, 0) & TRUST_MASK)
+      switch (get_validity (ctrl, key, uid, NULL, 0) & TRUST_MASK)
         {
         case TRUST_UNKNOWN:   return _("[ unknown]");
         case TRUST_EXPIRED:   return _("[ expired]");
         case TRUST_UNDEFINED: return _("[  undef ]");
+        case TRUST_NEVER:     return _("[  never ]");
         case TRUST_MARGINAL:  return _("[marginal]");
         case TRUST_FULLY:     return _("[  full  ]");
         case TRUST_ULTIMATE:  return _("[ultimate]");
@@ -274,19 +275,23 @@ revalidation_mark (void)
 
 
 void
-check_trustdb_stale (void)
+check_trustdb_stale (ctrl_t ctrl)
 {
 #ifndef NO_TRUST_MODELS
-  tdb_check_trustdb_stale ();
+  tdb_check_trustdb_stale (ctrl);
+#else
+  (void)ctrl;
 #endif
 }
 
 
 void
-check_or_update_trustdb (void)
+check_or_update_trustdb (ctrl_t ctrl)
 {
 #ifndef NO_TRUST_MODELS
-  tdb_check_or_update ();
+  tdb_check_or_update (ctrl);
+#else
+  (void)ctrl;
 #endif
 }
 
@@ -297,8 +302,8 @@ check_or_update_trustdb (void)
  * otherwise, a reasonable value for the entire key is returned.
  */
 unsigned int
-get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
-             int may_ask)
+get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
+              PKT_signature *sig, int may_ask)
 {
   int rc;
   unsigned int validity;
@@ -330,7 +335,7 @@ get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
 #ifdef NO_TRUST_MODELS
   validity = TRUST_UNKNOWN;
 #else
-  validity = tdb_get_validity_core (pk, uid, main_pk, sig, may_ask);
+  validity = tdb_get_validity_core (ctrl, pk, uid, main_pk, sig, may_ask);
 #endif
 
  leave:
@@ -352,14 +357,14 @@ get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
 
 
 int
-get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
+get_validity_info (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
 {
   int trustlevel;
 
   if (!pk)
     return '?';  /* Just in case a NULL PK is passed.  */
 
-  trustlevel = get_validity (pk, uid, NULL, 0);
+  trustlevel = get_validity (ctrl, pk, uid, NULL, 0);
   if ((trustlevel & TRUST_FLAG_REVOKED))
     return 'r';
   return trust_letter (trustlevel);
@@ -367,14 +372,14 @@ get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
 
 
 const char *
-get_validity_string (PKT_public_key *pk, PKT_user_id *uid)
+get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
 {
   int trustlevel;
 
   if (!pk)
     return "err";  /* Just in case a NULL PK is passed.  */
 
-  trustlevel = get_validity (pk, uid, NULL, 0);
+  trustlevel = get_validity (ctrl, pk, uid, NULL, 0);
   if ((trustlevel & TRUST_FLAG_REVOKED))
     return _("revoked");
   return trust_value_to_string (trustlevel);
index 195a006..527a23d 100644 (file)
@@ -70,7 +70,7 @@ static struct key_item *utk_list;      /* all ultimately trusted keys */
 
 static int pending_check_trustdb;
 
-static int validate_keys (int interactive);
+static int validate_keys (ctrl_t ctrl, int interactive);
 
 \f
 /**********************************************
@@ -494,7 +494,7 @@ init_trustdb ()
  * when a check is due.  This can be used to run the check from a crontab
  */
 void
-check_trustdb ()
+check_trustdb (ctrl_t ctrl)
 {
   init_trustdb();
   if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC
@@ -519,7 +519,7 @@ check_trustdb ()
            }
        }
 
-      validate_keys (0);
+      validate_keys (ctrl, 0);
     }
   else
     log_info (_("no need for a trustdb check with '%s' trust model\n"),
@@ -531,12 +531,12 @@ check_trustdb ()
  * Recreate the WoT.
  */
 void
-update_trustdb()
+update_trustdb (ctrl_t ctrl)
 {
-  init_trustdb();
+  init_trustdb ();
   if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC
       || opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU)
-    validate_keys (1);
+    validate_keys (ctrl, 1);
   else
     log_info (_("no need for a trustdb update with '%s' trust model\n"),
              trust_model_string(opt.trust_model));
@@ -565,14 +565,14 @@ trustdb_pending_check(void)
 /* If the trustdb is dirty, and we're interactive, update it.
    Otherwise, check it unless no-auto-check-trustdb is set. */
 void
-tdb_check_or_update (void)
+tdb_check_or_update (ctrl_t ctrl)
 {
-  if(trustdb_pending_check())
+  if (trustdb_pending_check ())
     {
-      if(opt.interactive)
-       update_trustdb();
-      else if(!opt.no_auto_check_trustdb)
-       check_trustdb();
+      if (opt.interactive)
+       update_trustdb (ctrl);
+      else if (!opt.no_auto_check_trustdb)
+       check_trustdb (ctrl);
     }
 }
 
@@ -938,7 +938,7 @@ tdb_cache_disabled_value (PKT_public_key *pk)
 
 
 void
-tdb_check_trustdb_stale (void)
+tdb_check_trustdb_stale (ctrl_t ctrl)
 {
   static int did_nextcheck=0;
 
@@ -968,7 +968,7 @@ tdb_check_trustdb_stale (void)
             {
               if (!opt.quiet)
                 log_info (_("checking the trustdb\n"));
-              validate_keys (0);
+              validate_keys (ctrl, 0);
             }
         }
     }
@@ -981,7 +981,8 @@ tdb_check_trustdb_stale (void)
  * by the TOFU code to record statistics.
  */
 unsigned int
-tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
+tdb_get_validity_core (ctrl_t ctrl,
+                       PKT_public_key *pk, PKT_user_id *uid,
                        PKT_public_key *main_pk,
                       PKT_signature *sig,
                       int may_ask)
@@ -1008,7 +1009,7 @@ tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return TRUST_UNKNOWN;
 
-  check_trustdb_stale();
+  check_trustdb_stale (ctrl);
 
   if(opt.trust_model==TM_DIRECT)
     {
@@ -1064,12 +1065,12 @@ tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
          user_ids ++;
 
          if (sig)
-           tl = tofu_register (main_pk, user_id->name,
+           tl = tofu_register (ctrl, main_pk, user_id->name,
                                sig->digest, sig->digest_len,
                                sig->timestamp, "unknown",
                                may_ask);
          else
-           tl = tofu_get_validity (main_pk, user_id->name, may_ask);
+           tl = tofu_get_validity (ctrl, main_pk, user_id->name, may_ask);
 
          if (tl == TRUST_EXPIRED)
            user_ids_expired ++;
@@ -1267,7 +1268,7 @@ enum_cert_paths_print (void **context, FILE *fp,
  ****************************************/
 
 static int
-ask_ownertrust (u32 *kid,int minimum)
+ask_ownertrust (ctrl_t ctrl, u32 *kid, int minimum)
 {
   PKT_public_key *pk;
   int rc;
@@ -1291,7 +1292,7 @@ ask_ownertrust (u32 *kid,int minimum)
     }
   else
     {
-      ot=edit_ownertrust(pk,0);
+      ot=edit_ownertrust (ctrl, pk, 0);
       if(ot>0)
        ot = tdb_get_ownertrust (pk);
       else if(ot==0)
@@ -1881,7 +1882,7 @@ reset_trust_records(void)
  *
  */
 static int
-validate_keys (int interactive)
+validate_keys (ctrl_t ctrl, int interactive)
 {
   int rc = 0;
   int quit=0;
@@ -1989,7 +1990,7 @@ validate_keys (int interactive)
 
           if (interactive && k->ownertrust == TRUST_UNKNOWN)
            {
-             k->ownertrust = ask_ownertrust (k->kid,min);
+             k->ownertrust = ask_ownertrust (ctrl, k->kid,min);
 
              if (k->ownertrust == (unsigned int)(-1))
                {
index 7e1307d..47d7b72 100644 (file)
@@ -83,20 +83,22 @@ void register_trusted_key (const char *string);
 
 const char *trust_value_to_string (unsigned int value);
 int string_to_trust_value (const char *str);
-const char *uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid);
+const char *uid_trust_string_fixed (ctrl_t ctrl,
+                                    PKT_public_key *key, PKT_user_id *uid);
 
 unsigned int get_ownertrust (PKT_public_key *pk);
 void update_ownertrust (PKT_public_key *pk, unsigned int new_trust);
 int clear_ownertrusts (PKT_public_key *pk);
 
 void revalidation_mark (void);
-void check_trustdb_stale (void);
-void check_or_update_trustdb (void);
+void check_trustdb_stale (ctrl_t ctrl);
+void check_or_update_trustdb (ctrl_t ctrl);
 
-unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid,
+unsigned int get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
                           PKT_signature *sig, int may_ask);
-int get_validity_info (PKT_public_key *pk, PKT_user_id *uid);
-const char *get_validity_string (PKT_public_key *pk, PKT_user_id *uid);
+int get_validity_info (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid);
+const char *get_validity_string (ctrl_t ctrl,
+                                 PKT_public_key *pk, PKT_user_id *uid);
 
 void mark_usable_uid_certs (kbnode_t keyblock, kbnode_t uidnode,
                             u32 *main_kid, struct key_item *klist,
@@ -115,22 +117,23 @@ void tdb_register_trusted_keyid (u32 *keyid);
 void tdb_register_trusted_key (const char *string);
 /* Returns whether KID is on the list of ultimately trusted keys.  */
 int tdb_keyid_is_utk (u32 *kid);
-void check_trustdb (void);
-void update_trustdb (void);
+void check_trustdb (ctrl_t ctrl);
+void update_trustdb (ctrl_t ctrl);
 int setup_trustdb( int level, const char *dbname );
 void how_to_fix_the_trustdb (void);
 const char *trust_model_string (int model);
 void init_trustdb( void );
-void tdb_check_trustdb_stale (void);
+void tdb_check_trustdb_stale (ctrl_t ctrl);
 void sync_trustdb( void );
 
 void tdb_revalidation_mark (void);
 int trustdb_pending_check(void);
-void tdb_check_or_update (void);
+void tdb_check_or_update (ctrl_t ctrl);
 
 int tdb_cache_disabled_value (PKT_public_key *pk);
 
-unsigned int tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
+unsigned int tdb_get_validity_core (ctrl_t ctrl,
+                                    PKT_public_key *pk, PKT_user_id *uid,
                                     PKT_public_key *main_pk,
                                    PKT_signature *sig, int may_ask);
 
@@ -158,6 +161,6 @@ void export_ownertrust(void);
 void import_ownertrust(const char *fname);
 
 /*-- pkclist.c --*/
-int edit_ownertrust (PKT_public_key *pk, int mode );
+int edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode);
 
 #endif /*G10_TRUSTDB_H*/
index f59f4d9..a873541 100644 (file)
@@ -246,9 +246,9 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
   if (err)
     goto leave;
 
-  err = gnupg_create_inbound_pipe (inbound);
+  err = gnupg_create_inbound_pipe (inbound, NULL, 0);
   if (!err)
-    err = gnupg_create_outbound_pipe (outbound);
+    err = gnupg_create_outbound_pipe (outbound, NULL, 0);
   if (err)
     {
       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
index 316b94a..a205081 100644 (file)
@@ -55,7 +55,6 @@ struct
   int quiet;          /* Be as quiet as possible.  */
   int dry_run;        /* Don't change any persistent data.  */
 
-  const char *homedir;         /* Configuration directory name.  */
   const char *config_filename; /* Name of the used config file.  */
 
   /* Filename of the AGENT program.  */
index 645730f..f3c20f5 100644 (file)
@@ -159,7 +159,7 @@ my_strusage( int level )
       break;
 
     case 31: p = "\nHome: "; break;
-    case 32: p = opt.homedir; break;
+    case 32: p = gnupg_homedir (); break;
 
     default: p = NULL; break;
     }
@@ -269,7 +269,6 @@ main ( int argc, char **argv)
     log_fatal ("error allocating session environment block: %s\n",
                strerror (errno));
 
-  opt.homedir = default_homedir ();
   /* Fixme: We enable verbose mode here because there is currently no
      way to do this when starting g13-syshelp.  To fix that we should
      add a g13-syshelp.conf file in /etc/gnupg.  */
@@ -393,7 +392,7 @@ main ( int argc, char **argv)
         case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
         case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
 
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
 
         case oFakedSystemTime:
           {
@@ -427,7 +426,8 @@ main ( int argc, char **argv)
   configname = NULL;
 
   if (!opt.config_filename)
-    opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);
+    opt.config_filename = make_filename (gnupg_homedir (),
+                                         G13_NAME".conf", NULL);
 
   if (log_get_errorcount(0))
     g13_exit(2);
@@ -472,7 +472,7 @@ main ( int argc, char **argv)
   /* Set the standard GnuPG random seed file.  */
   if (use_random_seed)
     {
-      char *p = make_filename (opt.homedir, "random_seed", NULL);
+      char *p = make_filename (gnupg_homedir (), "random_seed", NULL);
       gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
       xfree(p);
     }
index 4489b2f..0499a18 100644 (file)
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -247,7 +247,7 @@ my_strusage( int level )
       break;
 
     case 31: p = "\nHome: "; break;
-    case 32: p = opt.homedir; break;
+    case 32: p = gnupg_homedir (); break;
 
     default: p = NULL; break;
     }
@@ -391,8 +391,6 @@ main ( int argc, char **argv)
     log_fatal ("error allocating session environment block: %s\n",
                strerror (errno));
 
-  opt.homedir = default_homedir ();
-
   /* First check whether we have a config file on the commandline.  */
   orig_argc = argc;
   orig_argv = argv;
@@ -412,7 +410,7 @@ 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;
+        gnupg_set_homedir (pargs.r.ret_str);
     }
 
   /* Initialize the secure memory. */
@@ -446,7 +444,7 @@ main ( int argc, char **argv)
 
   /* Set the default option file */
   if (default_config )
-    configname = make_filename (opt.homedir, G13_NAME".conf", NULL);
+    configname = make_filename (gnupg_homedir (), G13_NAME".conf", NULL);
 
   argc        = orig_argc;
   argv        = orig_argv;
@@ -552,7 +550,7 @@ main ( int argc, char **argv)
            }
           break;
 
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
 
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
         case oGpgProgram: opt.gpg_program = pargs.r.ret_str;  break;
@@ -623,7 +621,8 @@ main ( int argc, char **argv)
   configname = NULL;
 
   if (!opt.config_filename)
-    opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);
+    opt.config_filename = make_filename (gnupg_homedir (),
+                                         G13_NAME".conf", NULL);
 
   if (log_get_errorcount(0))
     g13_exit(2);
@@ -690,7 +689,7 @@ main ( int argc, char **argv)
   /* Set the standard GnuPG random seed file.  */
   if (use_random_seed)
     {
-      char *p = make_filename (opt.homedir, "random_seed", NULL);
+      char *p = make_filename (gnupg_homedir (), "random_seed", NULL);
       gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
       xfree(p);
     }
index 33885d6..a96ec6e 100644 (file)
@@ -631,12 +631,12 @@ g13_server (ctrl_t ctrl)
 
   if (opt.verbose || opt.debug)
     {
-      char *tmp = NULL;
+      char *tmp;
 
       tmp = xtryasprintf ("Home: %s\n"
                           "Config: %s\n"
                           "%s",
-                          opt.homedir,
+                          gnupg_homedir (),
                           opt.config_filename,
                           hello);
       if (tmp)
index 6af5448..d74a7ef 100644 (file)
@@ -140,7 +140,6 @@ typedef struct _keybox_openpgp_info *keybox_openpgp_info_t;
 
 /* Don't know whether this is needed: */
 /*  static struct { */
-/*    const char *homedir; */
 /*    int dry_run; */
 /*    int quiet; */
 /*    int verbose; */
index 0a64bc4..66b33de 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -492,6 +492,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "error mentre s'enviava a «%s»: %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVÍS: els permissos són insegurs en %s «%s»\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "ha fallat l'actualització: %s\n"
 
@@ -509,10 +513,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: s'ha creat el directori\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "AVÍS: els permissos són insegurs en %s «%s»\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "base de dades de confiança: ha fallat la lectura (n=%d): %s\n"
 
@@ -2033,13 +2033,13 @@ msgstr "canvia la contrasenya"
 msgid "export keys"
 msgstr "exporta claus"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exporta claus a un servidor de claus"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importa claus d'un servidor de claus"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "cerca claus en un servidor de claus"
 
 msgid "update all keys from a keyserver"
@@ -2648,6 +2648,9 @@ msgstr "fes els conflictes de marques de temps només un avís"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|escriu informació d'estat en aquest FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Forma d'ús: gpgv [opcions] [fitxers] (-h per a veure l'ajuda)"
 
@@ -4168,6 +4171,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "No hi ha cap ID amb l'índex %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "arrodonida fins a %u bits\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4184,11 +4192,6 @@ msgstr "Quina grandària voleu? (1024) "
 msgid "Requested keysize is %u bits\n"
 msgstr "La grandària sol·licitada és %u bits\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "arrodonida fins a %u bits\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5913,14 +5916,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "error mentre s'enviava a «%s»: %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "no s'ha trobat la clau pública %08lX: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "error en la lectura de «%s»: %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5999,14 +5994,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -6014,6 +6009,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "error en la lectura de «%s»: %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "error en la creació de la contrasenya: %s\n"
 
@@ -6175,6 +6174,10 @@ msgstr ""
 "no és necessària una comprovació de la base de dades de confiança\n"
 "\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "no s'ha trobat la clau pública %08lX: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "si us plau, feu un --check-trustdb\n"
 
@@ -6253,6 +6256,10 @@ msgstr "desconeguda"
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "mai       "
+
 msgid "[marginal]"
 msgstr ""
 
index 535f74c..855b825 100644 (file)
--- a/po/cs.po
+++ b/po/cs.po
@@ -464,6 +464,12 @@ msgstr "chyba při získávání soli pro socket\n"
 msgid "error binding socket to '%s': %s\n"
 msgstr "chyba při přilepování socketu na „%s“: %s\n"
 
+# TODO: i18n of first %s
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Varování: přístupová práva %s „%s“ nejsou bezpečná\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "volání listen() selhalo: %s\n"
@@ -480,12 +486,6 @@ msgstr "nelze vytvořit adresář „%s“: %s\n"
 msgid "directory '%s' created\n"
 msgstr "adresář „%s“ vytvořen\n"
 
-# TODO: i18n of first %s
-#, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Varování: přístupová práva %s „%s“ nejsou bezpečná\n"
-
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "volání stat() na „%s“ selhalo: %s\n"
@@ -1869,13 +1869,13 @@ msgstr "změnit heslo"
 msgid "export keys"
 msgstr "exportovat klíče"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exportovat klíče na server klíčů"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importovat klíče ze serveru klíčů"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "vyhledat klíče na serveru klíčů"
 
 msgid "update all keys from a keyserver"
@@ -2453,6 +2453,9 @@ msgstr "pouze varování při konfliktu časového razítka"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|zapsat informace o stavu do tohoto FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Použití: gpg [volby] [soubory] (-h pro pomoc)"
 
@@ -3853,6 +3856,10 @@ msgid "No key with this keygrip\n"
 msgstr "Klíč s takovým keygripem neexistuje\n"
 
 #, c-format
+msgid "rounded to %u bits\n"
+msgstr "zaokrouhleno na %u bitů\n"
+
+#, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "klíč %s může mít délku v intervalu %u až %u bitů.\n"
 
@@ -3868,10 +3875,6 @@ msgstr "Jakou délku klíče si přejete? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Požadovaná délka klíče je %u bitů.\n"
 
-#, c-format
-msgid "rounded to %u bits\n"
-msgstr "zaokrouhleno na %u bitů\n"
-
 msgid "Please select which elliptic curve you want:\n"
 msgstr "Prosím, vyberte, kterou eliptickou křivku chcete:\n"
 
@@ -5533,15 +5536,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "chyba při odesílání dat: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "veřejný klíč %s nebyl nalezen: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error setting OCSP target: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "chyba při nastavování cíle OCSP: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5628,14 +5622,14 @@ msgstr[1] ""
 msgstr[2] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5643,6 +5637,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error setting OCSP target: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "chyba při nastavování cíle OCSP: %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "chyba při vytváření roury: %s\n"
@@ -5807,6 +5806,10 @@ msgstr "není nutné kontrolovat databázi důvěry s modelem „%s“\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "není nutné aktualizovat databázi důvěry s modelem „%s“\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "veřejný klíč %s nebyl nalezen: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "prosím proveďte --check-trustdb\n"
 
@@ -5886,6 +5889,11 @@ msgstr "[  neznámá   ]"
 msgid "[  undef ]"
 msgstr "[nedefinovaná]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "žádná"
+
 msgid "[marginal]"
 msgstr "[  částečná  ]"
 
index 7e6ff4b..e7d4b68 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -499,6 +499,11 @@ msgstr "fejl ved indhentelse af nonce for soklen\n"
 msgid "error binding socket to '%s': %s\n"
 msgstr "fejl ved binding af sokkel til »%s«: %s\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Advarsel: usikre rettigheder på %s »%s«\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "listen() mislykkedes: %s\n"
@@ -519,11 +524,6 @@ msgid "directory '%s' created\n"
 msgstr "mappe »%s« oprettet\n"
 
 #, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Advarsel: usikre rettigheder på %s »%s«\n"
-
-#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat() mislykkedes for »%s«: %s\n"
@@ -1985,13 +1985,13 @@ msgstr "ændr en adgangsfrase"
 msgid "export keys"
 msgstr "eksporter nøgler"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "eksporter nøgler til en nøgletjener"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importer nøgler fra en nøgleserver"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "søg efter nøgler på en nøgleserver"
 
 msgid "update all keys from a keyserver"
@@ -2593,6 +2593,9 @@ msgstr "giv kun tidsstempelkonflikter en advarsel"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|skriv statusinformation til denne FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Brug: gpgv [tilvalg] [filer] (-h for hjælp)"
 
@@ -4065,6 +4068,11 @@ msgstr "Ikke et gyldigt nøglegreb (forventer 40 hex cifre)\n"
 msgid "No key with this keygrip\n"
 msgstr "Ingen nøgle med dette nøglegreb\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "afrundet op til %u bit\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "%s nøgler kan være mellem %u og %u bit lange.\n"
@@ -4081,11 +4089,6 @@ msgstr "Hvilken nøglestørrelse ønsker du? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Ønsket nøglestørrelse er %u bit\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "afrundet op til %u bit\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5783,15 +5786,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "fejl under afsendelse af %s-kommando: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "offentlig nøgle %s blev ikke fundet: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error storing flags: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "fejl ved lagring af flag: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5872,14 +5866,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5887,6 +5881,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error storing flags: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "fejl ved lagring af flag: %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "fejl ved oprettelse af datakanal: %s\n"
@@ -6048,6 +6047,10 @@ msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr ""
 "intet behov for en opdatering af trustdb med troværdighedsmodellen »%s«\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "offentlig nøgle %s blev ikke fundet: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "udfør venligst en --check-trustdb\n"
 
@@ -6126,6 +6129,11 @@ msgstr "[  ukendt]"
 msgid "[  undef ]"
 msgstr "[  ej def]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "aldrig"
+
 msgid "[marginal]"
 msgstr "[marginal]"
 
index f5886ef..8bbd5d3 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gnupg-2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2016-05-04 11:03+0200\n"
+"PO-Revision-Date: 2016-06-16 17:04+0200\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
@@ -451,6 +451,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "Der Socket kann nicht an `%s' gebunden werden: %s\n"
 
 #, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Zugriffsrechte für '%s' können nicht gesetzt werden: %s\n"
+
+#, c-format
 msgid "listen() failed: %s\n"
 msgstr "Der listen()-Aufruf ist fehlgeschlagen: %s\n"
 
@@ -467,10 +471,6 @@ msgid "directory '%s' created\n"
 msgstr "Verzeichnis `%s' erzeugt\n"
 
 #, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Zugriffsrechte für '%s' können nicht gesetzt werden: %s\n"
-
-#, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat()-Aufruf für `%s' fehlgeschlagen: %s\n"
 
@@ -1861,13 +1861,13 @@ msgstr "Die Passphrase ändern"
 msgid "export keys"
 msgstr "Schlüssel exportieren"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "Schlüssel zu einem Schlü.server exportieren"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "Schlüssel von einem Schlü.server importieren"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "Schlüssel auf einem Schlü.server suchen"
 
 msgid "update all keys from a keyserver"
@@ -2446,6 +2446,9 @@ msgstr "differierende Zeitangaben sind kein Fehler"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|Statusinfo auf FD (Dateihandle) ausgeben"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr "|ALGO|Weise mit ALGO erstellte Signaturen zurück"
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Aufruf: gpgv [Optionen] [Dateien] (-h für Hilfe)"
 
@@ -3871,6 +3874,10 @@ msgid "No key with this keygrip\n"
 msgstr "Kein Schlüssel mit diesem \"Keygrip\"\n"
 
 #, c-format
+msgid "rounded to %u bits\n"
+msgstr "gerundet auf %u Bit\n"
+
+#, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "%s-Schlüssel können zwischen %u und %u Bit lang sein.\n"
 
@@ -3886,10 +3893,6 @@ msgstr "Welche Schlüssellänge wünschen Sie? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Die verlangte Schlüssellänge beträgt %u Bit\n"
 
-#, c-format
-msgid "rounded to %u bits\n"
-msgstr "gerundet auf %u Bit\n"
-
 msgid "Please select which elliptic curve you want:\n"
 msgstr "Bitte wählen Sie, welche elliptische Kurve Sie möchten:\n"
 
@@ -5553,14 +5556,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "Fehler beim Schreiben der TOFU Datenbank: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "Öffentlicher Schlüssel %s nicht gefunden: %s\n"
-
-#, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "Fehler beim Setzen der TOFU Binding Vertrauensstufe auf %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr "Die Bindung %s ist NICHT bekannt."
 
@@ -5641,8 +5636,8 @@ msgstr[0] " innerhalb des letzten Monats."
 msgstr[1] " innerhalb der letzten %ld Monate."
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 "Normalerweise ist lediglich ein Schlüssel mit einer Email-Adresse "
@@ -5654,8 +5649,8 @@ msgstr ""
 "ob der neue Schlüssel legitim ist."
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr "gGaAuUlLfF"
 
@@ -5663,6 +5658,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr "(G)ut, einmal (A)kzeptieren, (U)nbekannt, einmal ab(L)ehnen, (F)alsch?"
 
 #, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "Fehler beim Setzen der TOFU Binding Vertrauensstufe auf %s\n"
+
+#, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "Fehler beim Ändern der TOFU Richtlinie: %s\n"
 
@@ -5843,6 +5842,10 @@ msgstr "\"Trust-DB\"-Überprüfung ist beim `%s'-Vertrauensmodell nicht nötig\n
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "\"Trust-DB\"-Änderung ist beim `%s'-Vertrauensmodell nicht nötig\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "Öffentlicher Schlüssel %s nicht gefunden: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "Bitte ein --check-trustdb durchführen\n"
 
@@ -5912,22 +5915,25 @@ msgid "[ revoked]"
 msgstr "[ widerrufen]"
 
 msgid "[ expired]"
-msgstr "[  verfallen]"
+msgstr "[ verfallen ]"
 
 msgid "[ unknown]"
-msgstr "[  unbekannt]"
+msgstr "[ unbekannt ]"
 
 msgid "[  undef ]"
 msgstr "[undefiniert]"
 
+msgid "[  never ]"
+msgstr "[  niemals  ]"
+
 msgid "[marginal]"
-msgstr "[   marginal]"
+msgstr "[  marginal ]"
 
 msgid "[  full  ]"
 msgstr "[vollständig]"
 
 msgid "[ultimate]"
-msgstr "[  ultimativ]"
+msgstr "[ ultimativ ]"
 
 msgid ""
 "the signature could not be verified.\n"
index d4316dd..7e3fcf2 100644 (file)
--- a/po/el.po
+++ b/po/el.po
@@ -462,6 +462,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "óöÜëìá óôç áðïóôïëÞ ðñïò ôï `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ìç áóöáëåßò Üäåéåò óôï %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "ç åíçìÝñùóç áðÝôõ÷å: %s\n"
 
@@ -479,10 +483,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: êáôÜëïãïò äçìéïõñãÞèçêå\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ìç áóöáëåßò Üäåéåò óôï %s \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: read áðÝôõ÷å (n=%d): %s\n"
 
@@ -1963,13 +1963,13 @@ msgstr "
 msgid "export keys"
 msgstr "åîáãùãÞ êëåéäéþí"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "åîáãùãÞ êëåéäéþí óå Ýíá äéáêïìéóôÞ êëåéäéþí"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "åéóáãùãÞ êëåéäéþí áðü Ýíá äéáêïìéóôÞ êëåéäéþí"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "áíáæÞôçóç êëåéäéþí óå Ýíá äéáêïìéóôÞ êëåéäéþí"
 
 msgid "update all keys from a keyserver"
@@ -2570,6 +2570,9 @@ msgstr "
 msgid "|FD|write status info to this FD"
 msgstr "|FD|åããñáöÞ ôùí ðëçñïöïñéþí êáôÜóôáóçò óôï FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "×ñÞóç: gpgv [åðéëïãÝò] [áñ÷åßá] (-h ãéá âïÞèåéá)"
 
@@ -4070,6 +4073,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Äåí õðÜñ÷åé user ID ìå äåßêôç %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "óôñïããõëïðïéÞèçêå Ýùò ôá %u bits\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4086,11 +4094,6 @@ msgstr "
 msgid "Requested keysize is %u bits\n"
 msgstr "Ôï ìÝãåèïò êëåéäéïý ðïõ æçôÞèçêå åßíáé %u bits\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "óôñïããõëïðïéÞèçêå Ýùò ôá %u bits\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5778,14 +5781,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "óöÜëìá óôç áðïóôïëÞ ðñïò ôï `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "ôï äçìüóéï êëåéäß %08lX äåí âñÝèçêå: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ `%s': %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5864,14 +5859,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5879,6 +5874,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "óöÜëìá óôç äçìéïõñãßá ôçò öñÜóçò êëåéäß: %s\n"
 
@@ -6034,6 +6033,10 @@ msgstr "
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "äåí õðÜñ÷åé áíÜãêç ãéá Ýëåã÷ï ôçò trustdb\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "ôï äçìüóéï êëåéäß %08lX äåí âñÝèçêå: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "ðáñáêáëþ êÜíôå Ýíá --check-trustdb\n"
 
@@ -6112,6 +6115,10 @@ msgstr "
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "ðïôÝ     "
+
 msgid "[marginal]"
 msgstr ""
 
index 43b29a8..f8e64f5 100644 (file)
--- a/po/eo.po
+++ b/po/eo.po
@@ -463,6 +463,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "eraro dum sendo al '%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Averto: malsekuraj permesoj sur %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "aktualigo malsukcesis: %s\n"
 
@@ -479,10 +483,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: dosierujo kreita\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Averto: malsekuraj permesoj sur %s \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fido-datenaro: lego malsukcesis (n=%d): %s\n"
 
@@ -1949,13 +1949,13 @@ msgstr "
 msgid "export keys"
 msgstr "eksporti þlosilojn"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "eksporti þlosilojn al þlosilservilo"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importi þlosilojn de þlosilservilo"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "seræi þlosilojn æe þlosilservilo"
 
 msgid "update all keys from a keyserver"
@@ -2556,6 +2556,9 @@ msgstr "malkongruo de tempostampoj"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|skribi statusinformojn al FD (dosierpriskribilo)"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 #, fuzzy
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Uzado: gpg [opcioj] [dosieroj] (-h por helpo)"
@@ -4046,6 +4049,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Mankas uzantidentigilo kun indekso %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "rondigita øis %u bitoj\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4062,11 +4070,6 @@ msgstr "Kiun 
 msgid "Requested keysize is %u bits\n"
 msgstr "Petita þlosilgrando estas %u bitoj\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "rondigita øis %u bitoj\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5724,14 +5727,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "eraro dum sendo al '%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "publika þlosilo %08lX ne trovita: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "eraro dum legado de '%s': %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5810,14 +5805,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5825,6 +5820,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "eraro dum legado de '%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "eraro dum kreado de pasfrazo: %s\n"
 
@@ -5978,6 +5977,10 @@ msgstr "kontrolo de fido-datenaro ne estas bezonata\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "kontrolo de fido-datenaro ne estas bezonata\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "publika þlosilo %08lX ne trovita: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr ""
 
@@ -6054,6 +6057,9 @@ msgstr "nekonata versio"
 msgid "[  undef ]"
 msgstr ""
 
+msgid "[  never ]"
+msgstr ""
+
 msgid "[marginal]"
 msgstr ""
 
index 09fc298..385ea2b 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -515,6 +515,11 @@ msgstr "error obteniendo valor 
 msgid "error binding socket to '%s': %s\n"
 msgstr "error enlazando el socket con `%s': %s\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Aviso: permisos inseguros en %s \"%s\"\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "listen() falló: %s\n"
@@ -535,11 +540,6 @@ msgid "directory '%s' created\n"
 msgstr "directorio `%s' creado\n"
 
 #, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Aviso: permisos inseguros en %s \"%s\"\n"
-
-#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat() falló para `%s': %s\n"
@@ -2004,13 +2004,13 @@ msgstr "cambia una frase contrase
 msgid "export keys"
 msgstr "exporta claves"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exporta claves a un servidor de claves"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importa claves desde un servidor de claves"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "busca claves en un servidor de claves"
 
 msgid "update all keys from a keyserver"
@@ -2622,6 +2622,9 @@ msgstr "hacer que los conflictos de fecha-hora sean s
 msgid "|FD|write status info to this FD"
 msgstr "|DF|escribe información de estado en este descriptor de fichero"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Uso: gpgv [opciones] [ficheros] (-h para ayuda)"
 
@@ -4066,6 +4069,11 @@ msgstr "No es un keygrip v
 msgid "No key with this keygrip\n"
 msgstr "No hay claves con ese keygrip\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "redondeados a %u bits\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "las claves %s pueden tener entre %u y %u bits de longitud.\n"
@@ -4082,11 +4090,6 @@ msgstr "
 msgid "Requested keysize is %u bits\n"
 msgstr "El tamaño requerido es de %u bits\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "redondeados a %u bits\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5776,15 +5779,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "error enviando orden %s: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "clave pública %s no encontrada: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error storing flags: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "error almacenando parámetros: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5865,14 +5859,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5880,6 +5874,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error storing flags: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "error almacenando parámetros: %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "error creando tubería: %s\n"
@@ -6044,6 +6043,10 @@ msgstr ""
 "no es necesario comprobar la base de datos de confianza\n"
 "con el modelo `%s'\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "clave pública %s no encontrada: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "por favor haga un --check-trustdb\n"
 
@@ -6124,6 +6127,11 @@ msgstr "[desconocida]"
 msgid "[  undef ]"
 msgstr "[no definida]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "nunca"
+
 msgid "[marginal]"
 msgstr "[   dudosa  ]"
 
index ccd011b..4ca6566 100644 (file)
--- a/po/et.po
+++ b/po/et.po
@@ -460,6 +460,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "viga teate saatmisel serverile `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "HOIATUS: ebaturvalised õigused %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "uuendamine ebaõnnestus: %s\n"
 
@@ -477,10 +481,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: kataloog on loodud\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "HOIATUS: ebaturvalised õigused %s \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: lugemine ebaõnnestus (n=%d): %s\n"
 
@@ -1956,13 +1956,13 @@ msgstr "muuda parooli"
 msgid "export keys"
 msgstr "ekspordi võtmed"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "ekspordi võtmed võtmeserverisse"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "impordi võtmed võtmeserverist"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "otsi võtmeid võtmeserverist"
 
 msgid "update all keys from a keyserver"
@@ -2555,6 +2555,9 @@ msgstr "teata ajatemplite konfliktist ainult hoiatusega"
 msgid "|FD|write status info to this FD"
 msgstr "|FP|kirjuta olekuinfo sellesse failipidemesse"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Kasuta: gpgv [võtmed] [failid] (-h näitab abiinfot)"
 
@@ -4031,6 +4034,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Kasutaja ID numbriga %d puudub\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "ümardatud üles %u bitini\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4047,11 +4055,6 @@ msgstr "Millist v
 msgid "Requested keysize is %u bits\n"
 msgstr "Soovitud võtmepikkus on %u bitti\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "ümardatud üles %u bitini\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5703,14 +5706,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "viga teate saatmisel serverile `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "ei leia avalikku võtit %08lX: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "viga `%s' lugemisel: %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5789,14 +5784,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5804,6 +5799,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "viga `%s' lugemisel: %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "viga parooli loomisel: %s\n"
 
@@ -5957,6 +5956,10 @@ msgstr "trustdb kontrolliks puudub vajadus\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "trustdb kontrolliks puudub vajadus\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "ei leia avalikku võtit %08lX: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "palun tehke --check-trustdb\n"
 
@@ -6034,6 +6037,10 @@ msgstr "tundmatu"
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "mitte kunagi"
+
 msgid "[marginal]"
 msgstr ""
 
index 48b8b2e..1b93bce 100644 (file)
--- a/po/fi.po
+++ b/po/fi.po
@@ -477,6 +477,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "virhe lähettäessä kohteeseen \"%s\": %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "VAROITUS: oikeudet kohteessa %s \"%s\" eivät ole turvallisia\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "päivitys epäonnistui: %s\n"
 
@@ -494,10 +498,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: hakemisto luotu\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "VAROITUS: oikeudet kohteessa %s \"%s\" eivät ole turvallisia\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: luku epäonnistui (n=%d): %s\n"
 
@@ -1971,13 +1971,13 @@ msgstr "muuta salasanaa"
 msgid "export keys"
 msgstr "vie avaimia"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "vie avaimia palvelimelle"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "nouda avaimia avainpalvelimelta"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "etsi avaimia avainpalvelimelta"
 
 msgid "update all keys from a keyserver"
@@ -2571,6 +2571,9 @@ msgstr "käsittele aikaleimakonfliktit pelkkinä varoituksina"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|tilatiedot kirjoitetaan FD:iin"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Käyttö: gpgv [valitsimet] [tiedostot] (-h näyttää ohjeen)"
 
@@ -4057,6 +4060,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Indeksillä %d ei löydy käyttäjätunnusta\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "pyöristetty %u bittiin\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4073,11 +4081,6 @@ msgstr "Minkä kokoisen avaimen haluat? (1024) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Halutun avaimen koko on %u bittiä\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "pyöristetty %u bittiin\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5761,14 +5764,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "virhe lähettäessä kohteeseen \"%s\": %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "julkista avainta %08lX ei löydy: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5847,14 +5842,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5862,6 +5857,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "virhe luotaessa salasanaa: %s\n"
 
@@ -6016,6 +6015,10 @@ msgstr "trustdb:n tarkistusta ei tarvita\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "trustdb:n tarkistusta ei tarvita\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "julkista avainta %08lX ei löydy: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "tee --check-trustdb, kiitos\n"
 
@@ -6093,6 +6096,10 @@ msgstr "tuntematon "
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "ei koskaan"
+
 msgid "[marginal]"
 msgstr ""
 
index 33eea36..94ac188 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -461,6 +461,11 @@ msgstr "erreur de lecture du « nonce » de la socket\n"
 msgid "error binding socket to '%s': %s\n"
 msgstr "erreur de lien de la socket à « %s » : %s\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Avertissement : les droits de %s ne sont pas sûrs « %s »\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "échec de listen() : %s\n"
@@ -477,11 +482,6 @@ msgstr "impossible de créer le répertoire « %s » : %s\n"
 msgid "directory '%s' created\n"
 msgstr "répertoire « %s » créé\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Avertissement : les droits de %s ne sont pas sûrs « %s »\n"
-
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "échec de stat() pour « %s » : %s\n"
@@ -1898,13 +1898,13 @@ msgstr "modifier une phrase secrète"
 msgid "export keys"
 msgstr "exporter les clefs"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exporter les clefs vers un serveur de clefs"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importer les clefs d'un serveur de clefs"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "chercher les clefs avec un serveur de clefs"
 
 msgid "update all keys from a keyserver"
@@ -2496,6 +2496,9 @@ msgstr "convertir les conflits de date en avertissements"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|écrire l'état sur ce descripteur"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Utilisation : gpgv [options] [fichiers] (-h pour l'aide)"
 
@@ -3930,6 +3933,10 @@ msgid "No key with this keygrip\n"
 msgstr "Pas de clef avec ce keygrip\n"
 
 #, c-format
+msgid "rounded to %u bits\n"
+msgstr "arrondie à %u bits\n"
+
+#, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "les clefs %s peuvent faire une taille comprise entre %u et %u bits.\n"
 
@@ -3945,10 +3952,6 @@ msgstr "Quelle taille de clef désirez-vous ? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "La taille demandée est %u bits\n"
 
-#, c-format
-msgid "rounded to %u bits\n"
-msgstr "arrondie à %u bits\n"
-
 msgid "Please select which elliptic curve you want:\n"
 msgstr "Sélectionnez le type de courbe elliptique désiré :\n"
 
@@ -5669,15 +5672,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "erreur d'envoi de données : %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "clef publique %s introuvable : %s\n"
-
-#, fuzzy, c-format
-#| msgid "error setting OCSP target: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "erreur de configuration de la cible OCSP : %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5758,14 +5752,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5773,6 +5767,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error setting OCSP target: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "erreur de configuration de la cible OCSP : %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "erreur de création d'un tube : %s\n"
@@ -5936,6 +5935,10 @@ msgstr ""
 "inutile de mettre à jour la base de confiance avec le modèle de\n"
 "     confiance « %s »\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "clef publique %s introuvable : %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "veuillez faire un --check-trustdb\n"
 
@@ -6014,6 +6017,11 @@ msgstr "[ inconnue]"
 msgid "[  undef ]"
 msgstr "[indéfinie]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "jamais"
+
 msgid "[marginal]"
 msgstr "[marginale]"
 
index 7ea0c18..915deaf 100644 (file)
--- a/po/gl.po
+++ b/po/gl.po
@@ -464,6 +464,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "erro ao enviar a `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVISO: permisos inseguros en %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "a actualización fallou: %s\n"
 
@@ -481,10 +485,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: directorio creado\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "AVISO: permisos inseguros en %s \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "base de datos de confianza: fallou a lectura (n=%d): %s\n"
 
@@ -1964,13 +1964,13 @@ msgstr "cambia-lo contrasinal"
 msgid "export keys"
 msgstr "exportar chaves"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exportar chaves a un servidor de chaves"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importar chaves dun servidor de chaves"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "buscar chaves nun servidor de chaves"
 
 msgid "update all keys from a keyserver"
@@ -2565,6 +2565,9 @@ msgstr "converte-los conflictos de selo de data nun aviso"
 msgid "|FD|write status info to this FD"
 msgstr "|DF|escribi-la información de estado a este DF"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Uso: gpgv [opcións] [ficheiros] (-h para ve-la axuda)"
 
@@ -4068,6 +4071,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Non hai ID de usuario con índice %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "redondeado a %u bits\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4084,11 +4092,6 @@ msgstr "
 msgid "Requested keysize is %u bits\n"
 msgstr "O tamaño de chave requerido son %u bits\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "redondeado a %u bits\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5767,14 +5770,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "erro ao enviar a `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "non se atopou a chave pública %08lX: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "erro lendo `%s': %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5853,14 +5848,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5868,6 +5863,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "erro lendo `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "erro ao crea-lo contrasinal: %s\n"
 
@@ -6022,6 +6021,10 @@ msgstr "non se precisa comproba-la base de datos de confianza\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "non se precisa comproba-la base de datos de confianza\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "non se atopou a chave pública %08lX: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "por favor, execute con --check-trustdb\n"
 
@@ -6099,6 +6102,10 @@ msgstr "desco
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "nunca     "
+
 msgid "[marginal]"
 msgstr ""
 
index 539aa00..a37b430 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -460,6 +460,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "Hiba %s-ra/-re küldéskor: %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "FIGYELEM: nem biztonságos engedélyek: %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "Frissítés sikertelen: %s.\n"
 
@@ -477,10 +481,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: Könyvtárat létrehoztam.\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "FIGYELEM: nem biztonságos engedélyek: %s \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "Bizalmi adatbázis: olvasás sikertelen (n=%d): %s.\n"
 
@@ -1952,13 +1952,13 @@ msgstr "jelsz
 msgid "export keys"
 msgstr "kulcsok exportálása"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "kulcsok exportálása kulcsszerverre"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "kulcsok importálása kulcsszerverrõl"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "kulcsok keresése kulcsszerveren"
 
 msgid "update all keys from a keyserver"
@@ -2553,6 +2553,9 @@ msgstr "id
 msgid "|FD|write status info to this FD"
 msgstr "|ÁL|állapotinformációk írása ÁL állományleíróra"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Használat: gpgv [opciók] [fájlok] (-h a súgóhoz)"
 
@@ -4033,6 +4036,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Nincs %d indexû felhasználóazonosító!\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "Felkerekítve %u bitre.\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4049,11 +4057,6 @@ msgstr "Milyen kulcsm
 msgid "Requested keysize is %u bits\n"
 msgstr "A kívánt kulcsméret %u bit.\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "Felkerekítve %u bitre.\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5734,14 +5737,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "Hiba %s-ra/-re küldéskor: %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "A(z) %08lX nyilvános kulcsot nem találom: %s.\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "Hiba \"%s\" olvasásakor: %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5820,14 +5815,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5835,6 +5830,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "Hiba \"%s\" olvasásakor: %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "Hiba a jelszó létrehozásakor: %s.\n"
 
@@ -5989,6 +5988,10 @@ msgstr "Nincs sz
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "Nincs szükség a bizalmi adatbázis ellenõrzésére.\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "A(z) %08lX nyilvános kulcsot nem találom: %s.\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "Kérem, hajtson végre egy --check-trustdb parancsot!\n"
 
@@ -6066,6 +6069,10 @@ msgstr "Ismeretlen m
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "soha      "
+
 msgid "[marginal]"
 msgstr ""
 
index c017cd4..04a3e98 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -344,7 +344,7 @@ msgstr ""
 
 #, fuzzy
 msgid "use a log file for the server"
-msgstr "cari kunci di key server"
+msgstr "cari kunci di keyserver"
 
 msgid "|PGM|use PGM as the PIN-Entry program"
 msgstr ""
@@ -465,6 +465,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "kesalahan mengirim ke `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Peringatan: permisi tidak aman pada %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "gagal memperbarui: %s\n"
 
@@ -482,10 +486,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: direktori tercipta\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Peringatan: permisi tidak aman pada %s \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: read failed (n=%d): %s\n"
 
@@ -1955,14 +1955,14 @@ msgstr "ubah passphrase"
 msgid "export keys"
 msgstr "ekspor kunci"
 
-msgid "export keys to a key server"
-msgstr "ekspor kunci ke key server"
+msgid "export keys to a keyserver"
+msgstr "ekspor kunci ke keyserver"
 
-msgid "import keys from a key server"
-msgstr "impor kunci dari key server"
+msgid "import keys from a keyserver"
+msgstr "impor kunci dari keyserver"
 
-msgid "search for keys on a key server"
-msgstr "cari kunci di key server"
+msgid "search for keys on a keyserver"
+msgstr "cari kunci di keyserver"
 
 msgid "update all keys from a keyserver"
 msgstr "update semua kunci dari keyserver"
@@ -2558,6 +2558,9 @@ msgstr "buat timestamp konflik hanya sebagai peringatan"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|tulis info status ke FD ini"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Pemakaian: gpgv [opsi] [file] (-h untuk bantuan)"
 
@@ -4042,6 +4045,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Tidak ada ID user dengan index %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "dibulatkan hingga %u bit\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4058,11 +4066,6 @@ msgstr "Keysize yang anda inginkan? (1024) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Keysize yang diminta adalah %u bit\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "dibulatkan hingga %u bit\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5724,14 +5727,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "kesalahan mengirim ke `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "kunci publik %08lX tidak ditemukan: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "kesalahan membaca `%s': %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5810,14 +5805,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5825,6 +5820,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "kesalahan membaca `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "kesalahan penciptaan passphrase: %s\n"
 
@@ -5978,6 +5977,10 @@ msgstr "tidak perlu memeriksa trustdb\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "tidak perlu memeriksa trustdb\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "kunci publik %08lX tidak ditemukan: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "lakukanlah --check-trustdb\n"
 
@@ -6055,6 +6058,10 @@ msgstr "tidak dikenal"
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "tidak pernah..."
+
 msgid "[marginal]"
 msgstr ""
 
index 6b30fbd..86317d9 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -339,7 +339,7 @@ msgstr ""
 
 #, fuzzy
 msgid "use a log file for the server"
-msgstr "cerca delle chiavi su un key server"
+msgstr "cerca delle chiavi su un keyserver"
 
 msgid "|PGM|use PGM as the PIN-Entry program"
 msgstr ""
@@ -460,6 +460,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "errore leggendo `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "ATTENZIONE: i permessi \"%s\" di %s sono insicuri\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "aggiornamento fallito: %s\n"
 
@@ -477,10 +481,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: directory creata\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "ATTENZIONE: i permessi \"%s\" di %s sono insicuri\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: read fallita (n=%d): %s\n"
 
@@ -1962,17 +1962,17 @@ msgstr "cambia la passphrase"
 msgid "export keys"
 msgstr "esporta delle chiavi"
 
-msgid "export keys to a key server"
-msgstr "esporta le chiavi a un key server"
+msgid "export keys to a keyserver"
+msgstr "esporta le chiavi a un keyserver"
 
-msgid "import keys from a key server"
-msgstr "importa le chiavi da un key server"
+msgid "import keys from a keyserver"
+msgstr "importa le chiavi da un keyserver"
 
-msgid "search for keys on a key server"
-msgstr "cerca delle chiavi su un key server"
+msgid "search for keys on a keyserver"
+msgstr "cerca delle chiavi su un keyserver"
 
 msgid "update all keys from a keyserver"
-msgstr "aggiorna tutte le chiavi da un key server"
+msgstr "aggiorna tutte le chiavi da un keyserver"
 
 msgid "import/merge keys"
 msgstr "importa/aggiungi delle chiavi"
@@ -2564,6 +2564,9 @@ msgstr "segnala i conflitti di data solo con un avvertimento"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|scrivi le informazioni di stato sul FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Uso: gpgv [opzioni] [file] (-h per l'aiuto)"
 
@@ -4057,6 +4060,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Nessun user ID con l'indice %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "arrotondate a %u bit\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4073,11 +4081,6 @@ msgstr "Di che dimensioni vuoi la chiave? (1024) "
 msgid "Requested keysize is %u bits\n"
 msgstr "La dimensione richiesta della chiave è %u bit\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "arrotondate a %u bit\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5765,14 +5768,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "errore leggendo `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "chiave pubblica %08lX non trovata: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "errore leggendo `%s': %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5851,14 +5846,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5866,6 +5861,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "errore leggendo `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "errore nella creazione della passhprase: %s\n"
 
@@ -6020,6 +6019,10 @@ msgstr "non 
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "non è necessario un controllo del trustdb\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "chiave pubblica %08lX non trovata: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "per favore usa --check-trustdb\n"
 
@@ -6097,6 +6100,10 @@ msgstr "sconosciuto"
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "mai       "
+
 msgid "[marginal]"
 msgstr ""
 
index e138ede..7f284e1 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -4,13 +4,13 @@
 # IIDA Yosiaki <iida@gnu.org>, 1999, 2000, 2002, 2003, 2004.
 # Yoshihiro Kajiki <kajiki@ylug.org>, 1999.
 # Takashi P.KATOH, 2002.
-# NIIBE Yutaka <gniibe@fsij.org>, 2013, 2014, 2015.
+# NIIBE Yutaka <gniibe@fsij.org>, 2013, 2014, 2015, 2016.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gnupg 2.1.10\n"
+"Project-Id-Version: gnupg 2.1.12\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2015-12-21 21:21+0900\n"
+"PO-Revision-Date: 2016-06-07 14:12+0900\n"
 "Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n"
 "Language-Team: none\n"
 "Language: ja\n"
@@ -361,10 +361,8 @@ msgstr "クライアントが鍵に\"trusted\"マークをつけることを認
 msgid "allow presetting passphrase"
 msgstr "パスフレーズの事前設定を認める"
 
-#, fuzzy
-#| msgid "allow caller to override the pinentry"
 msgid "disallow caller to override the pinentry"
-msgstr "pinentryã\82\88ã\82\8aå\84ªå\85\88ã\81\97ã\81¦ã\83\91ã\82¹ã\83\95ã\83¬ã\83¼ã\82ºå\85¥å\8a\9bã\82\92èª\8dã\82\81ã\82\8b"
+msgstr "pinentryã\82\88ã\82\8aå\84ªå\85\88ã\81\97ã\81¦ã\83\91ã\82¹ã\83\95ã\83¬ã\83¼ã\82ºå\85¥å\8a\9bã\82\92èª\8dã\82\81ã\81ªã\81\84"
 
 msgid "allow passphrase to be prompted through Emacs"
 msgstr "Emacsを通じてパスフレーズを催促することを認める"
@@ -434,6 +432,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "'%s'でソケットのバインドのエラー: %s\n"
 
 #, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "'%s'の許可が設定できません: %s\n"
+
+#, c-format
 msgid "listen() failed: %s\n"
 msgstr "listen() に失敗しました: %s\n"
 
@@ -449,11 +451,6 @@ msgstr "ディレクトリ'%s'が作成できません: %s\n"
 msgid "directory '%s' created\n"
 msgstr "ディレクトリ'%s'が作成されました\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "警告: '%s'の安全でない許可 \"%s\"\n"
-
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "'%s'でstat()が失敗しました: %s\n"
@@ -709,10 +706,9 @@ msgstr "パイプのストリーム作成エラー: %s\n"
 msgid "error forking process: %s\n"
 msgstr "プロセスforkエラー: %s\n"
 
-#, fuzzy, c-format
-#| msgid "waiting for process %d to terminate failed: %s\n"
+#, c-format
 msgid "waiting for processes to terminate failed: %s\n"
-msgstr "プロセス%dの終了待ちが失敗: %s\n"
+msgstr "プロセスの終了待ちが失敗: %s\n"
 
 #, c-format
 msgid "error running '%s': probably not installed\n"
@@ -750,10 +746,9 @@ msgstr "ユーザによる取消し\n"
 msgid "problem with the agent\n"
 msgstr "エージェントに障害\n"
 
-#, fuzzy, c-format
-#| msgid "problem with the agent: %s\n"
+#, c-format
 msgid "problem with the agent (unexpected response \"%s\")\n"
-msgstr "エージェントに問題: %s\n"
+msgstr "エージェントに問題 (予期しない応答 \"%s\")\n"
 
 #, c-format
 msgid "can't disable core dumps: %s\n"
@@ -1154,10 +1149,9 @@ msgstr ""
 "外装の中にquoted printable文字があります。おそらくバグのあるMTAが使われたので"
 "しょう\n"
 
-#, fuzzy, c-format
-#| msgid "not human readable"
+#, c-format
 msgid "[ not human readable (%zu bytes: %s%s) ]"
-msgstr "人には読めません"
+msgstr "[ 人には読めません (%zuバイト: %s%s) ]"
 
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
@@ -1174,18 +1168,11 @@ msgstr "ユーザ注釈名は、一つより大きい'@'文字を含んではな
 msgid "a notation value must not use any control characters\n"
 msgstr "注釈名の値に制御文字を使ってはいけません\n"
 
-#, fuzzy
-#| msgid "a notation name must not contain more than one '@' character\n"
 msgid "a notation name may not contain an '=' character\n"
-msgstr "ユーザ注釈名は、一つより大きい'@'文字を含んではなりません\n"
+msgstr "ユーザ注釈名は、'='の文字を含んではなりません\n"
 
-#, fuzzy
-#| msgid ""
-#| "a notation name must have only printable characters or spaces, and end "
-#| "with an '='\n"
 msgid "a notation name must have only printable characters or spaces\n"
-msgstr ""
-"注釈名には印字可能な文字か空白のみを使い、'='で終わらなければなりません\n"
+msgstr "注釈名には印字可能な文字か空白のみを使わなければなりません\n"
 
 msgid "WARNING: invalid notation data found\n"
 msgstr "*警告*: 無効な注釈データを発見\n"
@@ -1197,19 +1184,17 @@ msgstr "プロキシ%sのクライアントへの問い合わせが失敗しま
 msgid "Enter passphrase: "
 msgstr "パスフレーズを入力: "
 
-#, fuzzy, c-format
-#| msgid "error creating keyring '%s': %s\n"
+#, c-format
 msgid "error getting version from '%s': %s\n"
-msgstr "鍵リング'%s'の作成エラー: %s\n"
+msgstr "%s'からバージョン取得エラー: %s\n"
 
 #, c-format
 msgid "server '%s' is older than us (%s < %s)"
-msgstr ""
+msgstr "サーバ'%s'はこちらより古いです(%s < %s)"
 
-#, fuzzy, c-format
-#| msgid "WARNING: %s overrides %s\n"
+#, c-format
 msgid "WARNING: %s\n"
-msgstr "*警告*: %sは%sより優先\n"
+msgstr "*警告*: %s\n"
 
 #, c-format
 msgid "OpenPGP card not available: %s\n"
@@ -1692,24 +1677,17 @@ msgstr "[ユーザIDが見つかりません]"
 msgid "(check argument of option '%s')\n"
 msgstr "(オプション'%s'の引数を確認ください)\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "Warning: value '%s' for option '%s' should be a long key ID or a "
-#| "fingerprint\n"
+#, c-format
 msgid "Warning: '%s' should be a long key ID or a fingerprint\n"
-msgstr ""
-"警告: 値'%s'(オプション'%s'に対する)は長い鍵IDかフィンガープリントであるべき"
-"です。\n"
+msgstr "警告: '%s'は長い鍵IDかフィンガープリントであるべきです。\n"
 
-#, fuzzy, c-format
-#| msgid "error closing %s: %s\n"
+#, c-format
 msgid "error looking up: %s\n"
-msgstr "'%s'でクローズのエラー: %s\n"
+msgstr "検索のエラー: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error searching the keyring: %s\n"
+#, c-format
 msgid "Warning: %s appears in the keyring %d times\n"
-msgstr "鍵リング探索エラー: %s\n"
+msgstr "警告: %sは鍵リングに%d回出現します\n"
 
 #, c-format
 msgid "automatically retrieved '%s' via %s\n"
@@ -1726,19 +1704,17 @@ msgstr "フィンガープリントがありません"
 msgid "secret key \"%s\" not found: %s\n"
 msgstr "秘密鍵\"%s\"が見つかりません: %s\n"
 
-#, fuzzy, c-format
-#| msgid "using \"%s\" as default secret key\n"
+#, c-format
 msgid "Warning: not using '%s' as default key: %s\n"
-msgstr "デフォルトの秘密鍵として\"%s\"を用います\n"
+msgstr "警告: デフォルトの秘密鍵として '%s' を用いません: %s\n"
 
-#, fuzzy, c-format
-#| msgid "using \"%s\" as default secret key\n"
+#, c-format
 msgid "using \"%s\" as default secret key for signing\n"
-msgstr "デフォルトの秘密鍵として\"%s\"を用います\n"
+msgstr "ã\83\87ã\83\95ã\82©ã\83«ã\83\88ã\81®ç½²å\90\8dç\94¨ã\81®ç§\98å¯\86é\8dµã\81¨ã\81\97ã\81¦\"%s\"ã\82\92ç\94¨ã\81\84ã\81¾ã\81\99\n"
 
 #, c-format
 msgid "all values passed to '%s' ignored\n"
-msgstr ""
+msgstr "'%s'に渡されたすべての値は無視されました\n"
 
 #, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
@@ -1826,13 +1802,13 @@ msgstr "パスフレーズの変更"
 msgid "export keys"
 msgstr "鍵をエクスポートする"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "鍵サーバに鍵をエクスポートする"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "鍵サーバから鍵をインポートする"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "鍵サーバの鍵を検索する"
 
 msgid "update all keys from a keyserver"
@@ -1859,10 +1835,8 @@ msgstr "メッセージ・ダイジェストを表示"
 msgid "run in server mode"
 msgstr "サーバ・モードで実行"
 
-#, fuzzy
-#| msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
 msgid "|VALUE|set the TOFU policy for a key"
-msgstr "|VALUE|TOFUポリシーを鍵に設定する(good, unknown, bad, ask, auto)"
+msgstr "|VALUE|TOFUポリシーを鍵に設定する"
 
 msgid "create ascii armored output"
 msgstr "ASCII形式の外装を作成"
@@ -2333,10 +2307,9 @@ msgstr "鍵サーバからの受信に失敗しました: %s\n"
 msgid "key export failed: %s\n"
 msgstr "鍵のエクスポートに失敗しました: %s\n"
 
-#, fuzzy, c-format
-#| msgid "key export failed: %s\n"
+#, c-format
 msgid "export as ssh key failed: %s\n"
-msgstr "のエクスポートに失敗しました: %s\n"
+msgstr "ssh鍵としてのエクスポートに失敗しました: %s\n"
 
 #, c-format
 msgid "keyserver search failed: %s\n"
@@ -2390,6 +2363,9 @@ msgstr "日時の矛盾を警告だけにします"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|このFDにステイタス情報を書き出す"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr "|ALGO|ALGOで作成された署名を拒絶する"
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "使い方: gpgv [オプション] [ファイル] (ヘルプは -h)"
 
@@ -2811,56 +2787,50 @@ msgstr "[失効]"
 msgid "[self-signature]"
 msgstr "[自己署名]"
 
-#, fuzzy, c-format
-#| msgid "key %s: unsupported public key algorithm\n"
+#, c-format
 msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
-msgstr "鍵%s: サポートしていない公開鍵アルゴリズムです\n"
+msgstr "サポートしていない公開鍵アルゴリズム(%d)の署名は確認できません: %s.\n"
 
-#, fuzzy, c-format
-#| msgid "card does not support digest algorithm %s\n"
+#, c-format
 msgid ""
 "can't check signature with unsupported message-digest algorithm %d: %s.\n"
-msgstr "カードはダイジェスト・アルゴリズム %s をサポートしていません\n"
+msgstr ""
+"サポートしていないメッセージ・ダイジェスト(%d)の署名は確認できません: %s.\n"
 
-#, fuzzy
-#| msgid "Good signature from"
 msgid " (reordered signatures follow)"
-msgstr "正しい署名"
+msgstr "(順番を変えた署名が続きます)"
 
-#, fuzzy, c-format
-#| msgid "key %s: %s\n"
+#, c-format
 msgid "key %s:\n"
-msgstr "鍵  %s: %s\n"
+msgstr "鍵  %s:\n"
 
-#, fuzzy, c-format
-#| msgid "User ID \"%s\": %d signature removed\n"
+#, c-format
 msgid "%d duplicate signature removed\n"
 msgid_plural "%d duplicate signatures removed\n"
-msgstr[0] "ユーザID \"%s\": %d の署名が除去されました\n"
+msgstr[0] "%d個の重複した署名が除去されました\n"
 
-#, fuzzy, c-format
-#| msgid "1 signature not checked due to a missing key\n"
+#, c-format
 msgid "%d signature not checked due to a missing key\n"
 msgid_plural "%d signatures not checked due to missing keys\n"
-msgstr[0] "鍵がないため1個の署名を検査しません\n"
+msgstr[0] "鍵がないため%d個の署名は検査しません\n"
 
-#, fuzzy, c-format
-#| msgid "%d bad signatures\n"
+#, c-format
 msgid "%d bad signature\n"
 msgid_plural "%d bad signatures\n"
-msgstr[0] "不正な署名%d個\n"
+msgstr[0] "%d個の不正な署名\n"
 
-#, fuzzy, c-format
-#| msgid "Good signature from"
+#, c-format
 msgid "%d signature reordered\n"
 msgid_plural "%d signatures reordered\n"
-msgstr[0] "正しい署名"
+msgstr[0] "%d個の正しい署名\n"
 
 #, c-format
 msgid ""
 "Warning: errors found and only checked self-signatures, run '%s' to check "
 "all signatures.\n"
 msgstr ""
+"警告: エラーがあり、自己署名だけ確認しました。'%s'を実行してすべての署名を確"
+"認ください。\n"
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3296,10 +3266,9 @@ msgstr "\"%s\"はフィンガープリントではありません\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "\"%s\" はプライマリ・フィンガープリントではありません\n"
 
-#, fuzzy, c-format
-#| msgid "read error in '%s': %s\n"
+#, c-format
 msgid "Invalid user ID '%s': %s\n"
-msgstr "'%s'で読み込みエラー: %s\n"
+msgstr "無効なユーザID '%s': %s\n"
 
 msgid "No matching user IDs."
 msgstr "マッチするユーザIDはありません。"
@@ -3426,8 +3395,7 @@ msgstr "この不明の署名を削除しますか? (y/N/q)"
 msgid "Really delete this self-signature? (y/N)"
 msgstr "この自己署名を本当に削除しますか? (y/N)"
 
-#, fuzzy, c-format
-#| msgid "Deleted %d signature.\n"
+#, c-format
 msgid "Deleted %d signature.\n"
 msgid_plural "Deleted %d signatures.\n"
 msgstr[0] "%d個の署名を削除しました。\n"
@@ -3442,8 +3410,7 @@ msgstr "無効"
 msgid "User ID \"%s\" compacted: %s\n"
 msgstr "ユーザID \"%s\" は、コンパクトになりました: %s\n"
 
-#, fuzzy, c-format
-#| msgid "User ID \"%s\": %d signature removed\n"
+#, c-format
 msgid "User ID \"%s\": %d signature removed\n"
 msgid_plural "User ID \"%s\": %d signatures removed\n"
 msgstr[0] "ユーザID \"%s\": %d の署名が除去されました\n"
@@ -3764,6 +3731,10 @@ msgid "No key with this keygrip\n"
 msgstr "このkeygripの鍵はありません\n"
 
 #, c-format
+msgid "rounded to %u bits\n"
+msgstr "%uビットに切り上げます\n"
+
+#, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "%s 鍵は %u から %u ビットの長さで可能です。\n"
 
@@ -3779,10 +3750,6 @@ msgstr "鍵長は? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "要求された鍵長は%uビット\n"
 
-#, c-format
-msgid "rounded to %u bits\n"
-msgstr "%uビットに切り上げます\n"
-
 msgid "Please select which elliptic curve you want:\n"
 msgstr "ご希望の楕円曲線を選択してください:\n"
 
@@ -4066,23 +4033,20 @@ msgstr "クリティカルな署名注釈: "
 msgid "Signature notation: "
 msgstr "署名注釈: "
 
-#, fuzzy, c-format
-#| msgid "%d good signatures\n"
+#, c-format
 msgid "%d good signature\n"
 msgid_plural "%d good signatures\n"
 msgstr[0] "正しい署名%d個\n"
 
-#, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
+#, c-format
 msgid "%d signature not checked due to an error\n"
 msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "エラーのため1個の署名を検査しません\n"
+msgstr[0] "エラーのため%d個の署名を検査しません\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: %lu key(s) skipped due to their large size\n"
+#, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
-msgstr[0] "*警告*: %lu 鍵がその大きさのためスキップされました\n"
+msgstr[0] "*警告*: %lu個の鍵がその大きさのためスキップされました\n"
 
 msgid "Keyring"
 msgstr "鍵リング"
@@ -4115,23 +4079,20 @@ msgstr "   カードシリアル番号 ="
 msgid "caching keyring '%s'\n"
 msgstr "鍵リング'%s'をキャッシュします\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys cached so far (%lu signatures)\n"
+#, c-format
 msgid "%lu keys cached so far (%lu signature)\n"
 msgid_plural "%lu keys cached so far (%lu signatures)\n"
-msgstr[0] "%lu個の鍵までキャッシュ済 (%lu個の署名)\n"
+msgstr[0] "これまで%lu個の鍵をキャッシュしました (%lu個の署名)\n"
 
-#, fuzzy, c-format
-#| msgid "flush the cache"
+#, c-format
 msgid "%lu key cached"
 msgid_plural "%lu keys cached"
-msgstr[0] "キャッシュをフラッシュします"
+msgstr[0] "%lu個の鍵をキャッシュしました"
 
-#, fuzzy, c-format
-#| msgid "1 bad signature\n"
+#, c-format
 msgid " (%lu signature)\n"
 msgid_plural " (%lu signatures)\n"
-msgstr[0] "不正な署名1個\n"
+msgstr[0] " (%lu個の不正な署名)\n"
 
 #, c-format
 msgid "%s: keyring created\n"
@@ -4172,8 +4133,7 @@ msgstr "無効な鍵サーバ・プロトコルです (us %d!=handler %d)\n"
 msgid "\"%s\" not a key ID: skipping\n"
 msgstr "\"%s\"鍵IDではありません: スキップします\n"
 
-#, fuzzy, c-format
-#| msgid "refreshing %d keys from %s\n"
+#, c-format
 msgid "refreshing %d key from %s\n"
 msgid_plural "refreshing %d keys from %s\n"
 msgstr[0] "%d本の鍵を%sから更新\n"
@@ -4200,10 +4160,8 @@ msgstr "鍵%sを%sからサーバ%sに要求\n"
 msgid "requesting key %s from %s\n"
 msgstr "鍵%sを%sに要求\n"
 
-#, fuzzy
-#| msgid "invalid keyserver options\n"
 msgid "no keyserver known\n"
-msgstr "無効な鍵サーバ・オプションです\n"
+msgstr "鍵サーバがわかりません\n"
 
 #, c-format
 msgid "sending key %s to %s\n"
@@ -4414,18 +4372,16 @@ msgstr "*警告*: ダイジェスト・アルゴリズム %s は廃止されて
 msgid "Note: signatures using the %s algorithm are rejected\n"
 msgstr "注意: アルゴリズム %s を用いた署名は拒否されました\n"
 
-#, fuzzy, c-format
-#| msgid "%s:%u: read error: %s\n"
+#, c-format
 msgid "(reported error: %s)\n"
-msgstr "%s:%u: 読み込みエラー: %s\n"
+msgstr "(報告されたエラー: %s)\n"
 
-#, fuzzy, c-format
-#| msgid "read error in '%s': %s\n"
+#, c-format
 msgid "(reported error: %s <%s>)\n"
-msgstr "'%s'で読み込みエラー: %s\n"
+msgstr "(報告されたエラー: %s <%s>)\n"
 
 msgid "(further info: "
-msgstr ""
+msgstr "(より詳細な情報: "
 
 #, c-format
 msgid "%s:%d: deprecated option \"%s\"\n"
@@ -4814,10 +4770,9 @@ msgstr "%s: スキップ: 公開鍵は使用禁止です\n"
 msgid "%s: skipped: public key already present\n"
 msgstr "%s: スキップ: 公開鍵はもうあります\n"
 
-#, fuzzy, c-format
-#| msgid "can't connect to '%s': %s\n"
+#, c-format
 msgid "can't encrypt to '%s'\n"
-msgstr "'%s'ã\81¸æ\8e¥ç¶\9aã\81§ã\81\8dã\81¾ã\81\9bã\82\93: %s\n"
+msgstr "'%s'ã\81«æ\9a\97å\8f·å\8c\96ã\81§ã\81\8dã\81¾ã\81\9bã\82\93\n"
 
 #, c-format
 msgid "option '%s' given, but no valid default keys given\n"
@@ -4959,13 +4914,10 @@ msgid ""
 "declare that a key shall not anymore be used.  It is not possible\n"
 "to retract such a revocation certificate once it has been published."
 msgstr ""
+"失効証明書は \"殺すスイッチ\" のようなもので、鍵がそれ以上使えない\n"
+"ように公に宣言するものです。一度発行されると、そのような失効証明書は\n"
+"撤回することはできません。"
 
-#, fuzzy
-#| msgid ""
-#| "Use it to revoke this key in case of a compromise or loss of\n"
-#| "the secret key.  However, if the secret key is still accessible,\n"
-#| "it is better to generate a new revocation certificate and give\n"
-#| "a reason for the revocation."
 msgid ""
 "Use it to revoke this key in case of a compromise or loss of\n"
 "the secret key.  However, if the secret key is still accessible,\n"
@@ -4975,26 +4927,21 @@ msgid ""
 msgstr ""
 "秘密鍵のコンプロマイズや紛失の場合、これを使ってこの鍵を失効させます。\n"
 "しかし、秘密鍵がまだアクセス可能である場合、新しい失効証明書を生成し、\n"
-"失効の理由をつける方がよいでしょう。"
+"失効の理由をつける方がよいでしょう。詳細は、GnuPGマニュアルのgpgコマンド \"--"
+"gen-revoke\"の記述をご覧ください。"
 
-#, fuzzy
-#| msgid ""
-#| "To avoid an accidental use of this file, a colon has been inserted\n"
-#| "before the 5 dashes below.  Remove this colon with a text editor\n"
-#| "before making use of this revocation certificate."
 msgid ""
 "To avoid an accidental use of this file, a colon has been inserted\n"
 "before the 5 dashes below.  Remove this colon with a text editor\n"
 "before importing and publishing this revocation certificate."
 msgstr ""
-"このファイルを誤って使うのを避けるため、以下ではコロンが5つのダッシュの前に挿"
-"入されます。\n"
-"ã\81\93ã\81®å¤±å\8a¹è¨¼æ\98\8eæ\9b¸ã\82\92使ã\81\86å\89\8dã\81«ã\81¯ã\83\86ã\82¯ã\82¹ã\83\88ã\83»ã\82¨ã\83\87ã\82£ã\82¿ã\81§ã\81\93ã\81®ã\82³ã\83­ã\83³ã\82\92å\89\8aé\99¤ã\81\97ã\81¦ã\81\8fã\81 ã\81\95ã\81\84ã\80\82"
+"このファイルを誤って使うのを避けるため、以下ではコロンが5つのダッシュ\n"
+"の前に挿入されます。この失効証明書をインポートして公開する前に、テク\n"
+"スト・エディタでこのコロンを削除してください。"
 
-#, fuzzy, c-format
-#| msgid "Revocation certificate created.\n"
+#, c-format
 msgid "revocation certificate stored as '%s.rev'\n"
-msgstr "失効証明書を作成。\n"
+msgstr "失効証明書を '%s.rev' に保管しました。\n"
 
 #, c-format
 msgid "secret key \"%s\" not found\n"
@@ -5088,34 +5035,28 @@ msgstr "詳細は%sをご覧ください\n"
 msgid "WARNING: signing subkey %s has an invalid cross-certification\n"
 msgstr "*警告*: 無効な相互証明が、署名副鍵%sにあります\n"
 
-#, fuzzy, c-format
-#| msgid "public key %s is %lu second newer than the signature\n"
+#, c-format
 msgid "public key %s is %lu second newer than the signature\n"
 msgid_plural "public key %s is %lu seconds newer than the signature\n"
-msgstr[0] "公開鍵%sは、署名よりも%lu秒新しいものです\n"
+msgstr[0] "公開鍵%sは、署名よりも%lu秒新しいものです\n"
 
-#, fuzzy, c-format
-#| msgid "public key %s is %lu second newer than the signature\n"
+#, c-format
 msgid "public key %s is %lu day newer than the signature\n"
 msgid_plural "public key %s is %lu days newer than the signature\n"
-msgstr[0] "公開鍵%sは、署名よりも%lu新しいものです\n"
+msgstr[0] "公開鍵%sは、署名よりも%lu日、新しいものです\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid ""
 "key %s was created %lu second in the future (time warp or clock problem)\n"
 msgid_plural ""
 "key %s was created %lu seconds in the future (time warp or clock problem)\n"
-msgstr[0] "鍵%sは%lu秒未来にできました (時間歪曲か時計の障害でしょう)\n"
+msgstr[0] "鍵%sは%lu秒未来にできました (時間歪曲か時計の障害でしょう)\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid "key %s was created %lu day in the future (time warp or clock problem)\n"
 msgid_plural ""
 "key %s was created %lu days in the future (time warp or clock problem)\n"
-msgstr[0] "鍵%sは%lu未来にできました (時間歪曲か時計の障害でしょう)\n"
+msgstr[0] "鍵%sは%lu日、未来にできました (時間歪曲か時計の障害でしょう)\n"
 
 #, c-format
 msgid "Note: signature key %s expired %s\n"
@@ -5334,204 +5275,192 @@ msgstr "%d文字以上の長さのテキスト行は、取り扱えません\n"
 msgid "input line longer than %d characters\n"
 msgstr "入力行の長さが%d文字を超えています\n"
 
-#, fuzzy, c-format
-#| msgid "error sending standard options: %s\n"
+#, c-format
 msgid "error beginning transaction on TOFU database: %s\n"
-msgstr "標準オプションを送信エラー: %s\n"
+msgstr "TOFUデータベースのトランザクション開始エラー: %s\n"
 
 #, c-format
 msgid "error committing transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "TOFUデータベースのトランザクションコミットのエラー: %s\n"
 
 #, c-format
 msgid "error rolling back transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "TOFUデータベースのトランザクションのロールバックのエラー: %s\n"
 
-#, fuzzy, c-format
-#| msgid "unsupported algorithm: %s"
+#, c-format
 msgid "unsupported TOFU database version: %s\n"
-msgstr "サポートされていないアルゴリズム: %s"
+msgstr "サポートされていないTOFUデータベースバージョン: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
+#, c-format
 msgid "error reading TOFU database: %s\n"
-msgstr "データ送信エラー: %s\n"
+msgstr "TOFUデータベースの読み込みエラー: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error writing base64 encoding: %s\n"
+#, c-format
 msgid "error determining TOFU database's version: %s\n"
-msgstr "base64エンコーディングの書き込みエラー: %s\n"
+msgstr "TOFUデータベースのバージョン判定エラー: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error initializing reader object: %s\n"
+#, c-format
 msgid "error initializing TOFU database: %s\n"
-msgstr "リーダ・オブジェクトの初期化エラー: %s\n"
+msgstr "TOFUデータベースの初期化エラー: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error opening '%s': %s\n"
+#, c-format
 msgid "error opening TOFU database '%s': %s\n"
-msgstr "'%s'を開く際、エラー: %s\n"
+msgstr "TOFUデータベースのオープンでエラー '%s': %s\n"
 
 msgid "Warning: Home directory contains both tofu.db and tofu.d.\n"
-msgstr ""
+msgstr "警告: tofu.db と tofu.d の両方がホームディレクトリにあります。\n"
 
 msgid "Using split format for TOFU database\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
-msgid "error updating TOFU database: %s\n"
-msgstr "データ送信エラー: %s\n"
+msgstr "TOFUデータベースに分割フォーマットを使用\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "公開鍵%sが見つかりません: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error setting OCSP target: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "OCSPターゲットの設定エラー: %s\n"
+msgid "error updating TOFU database: %s\n"
+msgstr "TOFUデータベースの更新エラー: %s\n"
 
 #, c-format
 msgid "The binding %s is NOT known."
-msgstr ""
+msgstr "%sのバインディングは不明です。"
 
 #, c-format
 msgid ""
 "The key with fingerprint %s raised a conflict with the binding %s.  Since "
 "this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
+"鍵のフィンガープリント%sがバインディング%sと衝突しました。このバインディング"
+"ポリシーは'auto'だったので、'ask'に変更されました。"
 
 #, c-format
 msgid ""
 "Please indicate whether you believe the binding %s%sis legitimate (the key "
 "belongs to the stated owner) or a forgery (bad)."
 msgstr ""
+"バインディング%s%sが適切(鍵は述べられた所有者に属する)か、偽られたものか(ダ"
+"メ)かを指示してください。"
 
-#, fuzzy, c-format
-#| msgid "error getting responder ID: %s\n"
+#, c-format
 msgid "error gathering other user IDs: %s\n"
-msgstr "応答IDの取得エラー: %s\n"
+msgstr "ほかのユーザIDの収集エラー: %s\n"
 
 msgid "Known user IDs associated with this key:\n"
-msgstr ""
+msgstr "この鍵に結びつけられた知られているユーザID:\n"
 
-#, fuzzy, c-format
-#| msgid "validity: %s"
+#, c-format
 msgid "policy: %s"
-msgstr "有効性: %s"
+msgstr "ポリシー: %s"
 
-#, fuzzy, c-format
-#| msgid "error getting stored flags: %s\n"
+#, c-format
 msgid "error gathering signature stats: %s\n"
-msgstr "保存されたフラグの取得エラー: %s\n"
+msgstr "署名の統計の収集エラー: %s\n"
 
 #, c-format
 msgid "The email address \"%s\" is associated with %d key:\n"
 msgid_plural "The email address \"%s\" is associated with %d keys:\n"
-msgstr[0] ""
+msgstr[0] "電子メールアドレス\"%s\"は%d個の鍵に結びつけられます:\n"
 
 #, c-format
 msgid "Statistics for keys with the email address \"%s\":\n"
-msgstr ""
+msgstr "この電子メールアドレス\"%s\"の鍵の統計:\n"
 
-#, fuzzy
-#| msgid "list keys"
 msgid "this key"
-msgstr "鍵の一覧"
+msgstr "この鍵"
 
 #, c-format
 msgid "%ld message signed in the future."
 msgid_plural "%ld messages signed in the future."
-msgstr[0] ""
+msgstr[0] "%ld個のメッセージが未来に署名されました。"
 
-#, fuzzy, c-format
-#| msgid "print message digests"
+#, c-format
 msgid "%ld message signed"
 msgid_plural "%ld messages signed"
-msgstr[0] "メッセージ・ダイジェストを表示"
+msgstr[0] "%ld個のメッセージに署名しました"
 
 #, c-format
 msgid " over the past %ld day."
 msgid_plural " over the past %ld days."
-msgstr[0] ""
+msgstr[0] "過去%ld日に。"
 
 #, c-format
 msgid " over the past %ld week."
 msgid_plural " over the past %ld weeks."
-msgstr[0] ""
+msgstr[0] "過去%ld週間に。"
 
 #, c-format
 msgid " over the past %ld month."
 msgid_plural " over the past %ld months."
-msgstr[0] ""
+msgstr[0] "過去%ld月に。"
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
-msgstr ""
+msgstr "TOFUはバインディングの衝突を検出しました"
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
-msgstr ""
+msgstr "gGaAuUrRbB"
 
 msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
+"(G)ood-良, (A)ccept once-一度だけ良, (U)nknown-不明, (R)eject once-一度だけ"
+"否, (B)ad-ダメ? "
 
-#, fuzzy, c-format
-#| msgid "error creating a pipe: %s\n"
+#, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "TOFUデータベースの信用レベルの設定エラー: %s\n"
+
+#, c-format
 msgid "error changing TOFU policy: %s\n"
-msgstr "パイプの作成エラー: %s\n"
+msgstr "TOFUポリシーの作成エラー: %s\n"
 
 #. TRANSLATORS: The tilde ('~') is used here to indicate a
 #. * non-breakable space
 #, c-format
 msgid "%d~year"
 msgid_plural "%d~years"
-msgstr[0] ""
+msgstr[0] "%d~年"
 
 #, c-format
 msgid "%d~month"
 msgid_plural "%d~months"
-msgstr[0] ""
+msgstr[0] "%d~月"
 
 #, c-format
 msgid "%d~day"
 msgid_plural "%d~days"
-msgstr[0] ""
+msgstr[0] "%d~月"
 
 #, c-format
 msgid "%d~hour"
 msgid_plural "%d~hours"
-msgstr[0] ""
+msgstr[0] "%d~時間"
 
 #, c-format
 msgid "%d~minute"
 msgid_plural "%d~minutes"
-msgstr[0] ""
+msgstr[0] "%d~分"
 
 #, c-format
 msgid "%d~second"
 msgid_plural "%d~seconds"
-msgstr[0] ""
+msgstr[0] "%d~秒"
 
 #, c-format
 msgid "Have never verified a message signed by key %s!\n"
-msgstr ""
+msgstr "鍵%sで署名されたメッセージを検証したことは一度もありません!\n"
 
 #, c-format
 msgid ""
 "Failed to collect signature statistics for \"%s\"\n"
 "(key %s)\n"
 msgstr ""
+"\"%s\"の署名の統計を収集することに失敗しました\n"
+"(鍵 %s)\n"
 
-#, fuzzy, c-format
-#| msgid "print message digests"
+#, c-format
 msgid "Verified %ld messages signed by \"%s\"."
-msgstr "メッセージ・ダイジェストを表示"
+msgstr "%ld個のメッセージを検証しました(\"%s\"で署名されたもの)。"
 
 #, c-format
 msgid ""
@@ -5540,17 +5469,18 @@ msgid ""
 msgid_plural ""
 "Verified %ld messages signed by \"%s\"\n"
 "in the past %s."
-msgstr[0] ""
+msgstr[0] "メッセージを%ld回検証しました(\"%s\"で署名されたもの。かつて %s)。"
 
 #, c-format
 msgid "The most recent message was verified %s ago."
-msgstr ""
+msgstr "もっとも最近のメッセージは%s前に検証されました。"
 
 msgid "Warning: we've have yet to see a message signed by this key!\n"
-msgstr ""
+msgstr "警告: この鍵で署名されたメッセージを検証したことはありません!\n"
 
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
+"警告: この鍵で署名されたメッセージを検証したことは一度しかありません!\n"
 
 #, c-format
 msgid ""
@@ -5566,11 +5496,15 @@ msgid_plural ""
 "  %s\n"
 "to mark it as being bad.\n"
 msgstr[0] ""
+"警告: この鍵で署名されたメッセージを%ld回以上見たと思う場合、偽者の可能性があ"
+"ります! 少数のバリエーションでこの電子メールアドレスを注意深く検査してくださ"
+"い。この鍵が疑われる場合、\n"
+"  %s\n"
+"でダメとマークしてください。\n"
 
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
+#, c-format
 msgid "error opening TOFU database: %s\n"
-msgstr "データ送信エラー: %s\n"
+msgstr "TOFUデータベースのオープンでエラー: %s\n"
 
 #, c-format
 msgid "'%s' is not a valid long keyID\n"
@@ -5629,23 +5563,25 @@ msgstr "信用モデル'%s'で信用データベースの検査は、不要で
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "信用モデル'%s'で信用データベースの更新は、不要です\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "公開鍵%sが見つかりません: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "--check-trustdbを実行してください\n"
 
 msgid "checking the trustdb\n"
 msgstr "信用データベースの検査\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys processed so far\n"
+#, c-format
 msgid "%d key processed"
 msgid_plural "%d keys processed"
-msgstr[0] "これまで%lu個の鍵を処理\n"
+msgstr[0] "%d個の鍵を処理"
 
-#, fuzzy, c-format
-#| msgid "%d keys processed (%d validity counts cleared)\n"
+#, c-format
 msgid " (%d validity count cleared)\n"
 msgid_plural " (%d validity counts cleared)\n"
-msgstr[0] "%d本の鍵を処理 (うち%d本の有効性数をクリア)\n"
+msgstr[0] " (うち%d本の有効性数をクリア)\n"
 
 msgid "no ultimately trusted keys found\n"
 msgstr "究極的に信用する鍵が見つかりません\n"
@@ -5669,7 +5605,7 @@ msgid "undefined"
 msgstr "未定義"
 
 msgid "never"
-msgstr "断じてなし"
+msgstr "全くなし"
 
 msgid "marginal"
 msgstr "まぁまぁ"
@@ -5703,6 +5639,9 @@ msgstr "[  不明  ]"
 msgid "[  undef ]"
 msgstr "[ 未定義 ]"
 
+msgid "[  never ]"
+msgstr "[全くなし]"
+
 msgid "[marginal]"
 msgstr "[まぁまぁ]"
 
@@ -5849,8 +5788,7 @@ msgstr "カードからCHVステイタスの取得でエラー\n"
 msgid "card is permanently locked!\n"
 msgstr "カードが永久にロックされてます!\n"
 
-#, fuzzy, c-format
-#| msgid "%d Admin PIN attempts remaining before card is permanently locked\n"
+#, c-format
 msgid "%d Admin PIN attempt remaining before card is permanently locked\n"
 msgid_plural ""
 "%d Admin PIN attempts remaining before card is permanently locked\n"
@@ -5931,8 +5869,7 @@ msgstr "鍵生成の間、お待ちください ...\n"
 msgid "generating key failed\n"
 msgstr "鍵の生成に失敗しました\n"
 
-#, fuzzy, c-format
-#| msgid "key generation completed (%d seconds)\n"
+#, c-format
 msgid "key generation completed (%d second)\n"
 msgid_plural "key generation completed (%d seconds)\n"
 msgstr[0] "鍵の生成が完了しました (%d秒)\n"
@@ -8029,10 +7966,8 @@ msgstr "|N|N日後にパスフレーズを期限切れとする"
 msgid "do not allow the reuse of old passphrases"
 msgstr "古いパスフレーズを再使用することを認めない"
 
-#, fuzzy
-#| msgid "|N|set LDAP timeout to N seconds"
 msgid "|N|set the Pinentry timeout to N seconds"
-msgstr "|N|LDAPのタイムアウトをN秒とする"
+msgstr "|N|PinentryのタイムアウトをN秒とする"
 
 msgid "|NAME|use NAME as default secret key"
 msgstr "|NAME|デフォルトの秘密鍵としてNAMEを用いる"
@@ -8324,12 +8259,6 @@ msgstr ""
 #~ msgid "you found a bug ... (%s:%d)\n"
 #~ msgstr "あなたはバグを発見しました ... (%s:%d)\n"
 
-#, fuzzy
-#~| msgid "%d user IDs without valid self-signatures detected\n"
-#~ msgid "%d user ID without valid self-signature detected\n"
-#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
-#~ msgstr[0] "有効な自己署名のないユーザIDを%d個検出\n"
-
 #~ msgid "moving a key signature to the correct place\n"
 #~ msgstr "鍵の署名を正しい場所に移動します\n"
 
index 970241e..9844310 100644 (file)
--- a/po/nb.po
+++ b/po/nb.po
@@ -466,6 +466,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "feil ved søking etter tillitspost i «%s»: %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "ADVARSEL: utrygge rettigheter på utvidelsen «%s»\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "oppdatering mislyktes: %s\n"
 
@@ -484,10 +488,6 @@ msgid "directory '%s' created\n"
 msgstr "katalogen «%s» ble opprettet\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "ADVARSEL: utrygge rettigheter på utvidelsen «%s»\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fstat(%d) mislyktes in %s: %s\n"
 
@@ -1915,13 +1915,13 @@ msgstr "endre passfrasen"
 msgid "export keys"
 msgstr "eksportere nøkler"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "eksportere nøkler til en nøkkelserver"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importere nøkler fra en nøkkelserver"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "søke etter nøkler på en nøkkelserver"
 
 msgid "update all keys from a keyserver"
@@ -2533,6 +2533,9 @@ msgstr "la konflikter mellom tidsstempler bare v
 msgid "|FD|write status info to this FD"
 msgstr "|FD|skrive statusinfo til denne FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Bruksmåte: gpgv [valg] [filer] (-h for hjelp)"
 
@@ -3933,6 +3936,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "rundet opp til %u bits\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -3949,11 +3957,6 @@ msgstr "Hvilken n
 msgid "Requested keysize is %u bits\n"
 msgstr "Ønsket nøkkelstørrelse er %u bits\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "rundet opp til %u bits\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5604,14 +5607,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "feil ved lesing av «%s»: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "fant ikke offentlig nøkkel %s: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "feil ved lesing av «%s»: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5690,14 +5685,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5705,6 +5700,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "feil ved lesing av «%s»: %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "feil ved opprettelse av passfrase: %s\n"
 
@@ -5858,6 +5857,10 @@ msgstr ""
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr ""
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "fant ikke offentlig nøkkel %s: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr ""
 
@@ -5931,6 +5934,9 @@ msgstr "[ ukjent]"
 msgid "[  undef ]"
 msgstr "[ udef ]"
 
+msgid "[  never ]"
+msgstr ""
+
 msgid "[marginal]"
 msgstr ""
 
index 2b8c12c..075ec76 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -488,6 +488,11 @@ msgstr "b
 msgid "error binding socket to '%s': %s\n"
 msgstr "b³±d podczas przypisywania gniazda do ,,%s'': %s\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Ostrze¿enie: niebezpieczne prawa dostêpu do %s ,,%s''\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "listen() nie powiod³o siê: %s\n"
@@ -508,11 +513,6 @@ msgid "directory '%s' created\n"
 msgstr "katalog ,,%s'' utworzony\n"
 
 #, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Ostrze¿enie: niebezpieczne prawa dostêpu do %s ,,%s''\n"
-
-#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat() nie powiod³o siê dla ,,%s'': %s\n"
@@ -1970,13 +1970,13 @@ msgstr "zmiana has
 msgid "export keys"
 msgstr "eksport kluczy do pliku"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "eksport kluczy do serwera kluczy"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "import kluczy z serwera kluczy"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "szukanie kluczy na serwerze"
 
 msgid "update all keys from a keyserver"
@@ -2601,6 +2601,9 @@ msgstr "nie traktowa
 msgid "|FD|write status info to this FD"
 msgstr "|FD|pisanie opisu stanu do deskryptora FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Wywo³anie: gpgv [opcje] [pliki] (-h podaje pomoc)"
 
@@ -4077,6 +4080,11 @@ msgstr "Nieprawid
 msgid "No key with this keygrip\n"
 msgstr "Brak klucza o tym uchwycie\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "zaokr±glono do %u bitów\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "Klucze %s bêd± mia³y od %u do %u bitów d³ugo¶ci.\n"
@@ -4093,11 +4101,6 @@ msgstr "Jakiej d
 msgid "Requested keysize is %u bits\n"
 msgstr "¯±dana d³ugo¶æ klucza to %u bitów.\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "zaokr±glono do %u bitów\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5825,15 +5828,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "b³±d wysy³ania polecenia %s: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "klucz publiczny %s nie odnaleziony: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error storing flags: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "b³±d zapisywania flag: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5920,14 +5914,14 @@ msgstr[1] ""
 msgstr[2] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5935,6 +5929,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error storing flags: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "b³±d zapisywania flag: %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "b³±d tworzenia potoku: %s\n"
@@ -6102,6 +6101,10 @@ msgstr "sprawdzanie bazy jest niepotrzebne przy modelu zaufania ,,%s''\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "aktualizacja bazy jest niepotrzebna przy modelu zaufania ,,%s''\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "klucz publiczny %s nie odnaleziony: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "nale¿y uruchomiæ gpg z opcj± ,,--check-trustdb''\n"
 
@@ -6184,6 +6187,11 @@ msgstr "[    nieznane   ]"
 msgid "[  undef ]"
 msgstr "[  nieokre¶lone ]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "nigdy"
+
 msgid "[marginal]"
 msgstr "[   marginalne  ]"
 
index c271492..e20d484 100644 (file)
--- a/po/pt.po
+++ b/po/pt.po
@@ -465,6 +465,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "erro ao enviar para `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVISO: permissões pouco seguras em %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "actualização falhou: %s\n"
 
@@ -481,10 +485,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: directoria criada\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "AVISO: permissões pouco seguras em %s \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "base de dados de confiança: leitura falhou (n=%d): %s\n"
 
@@ -1954,13 +1954,13 @@ msgstr "muda a frase secreta"
 msgid "export keys"
 msgstr "exportar chaves"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exportar chaves para um servidor de chaves"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importar chaves de um servidor de chaves"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "procurar chaves num servidor de chaves"
 
 msgid "update all keys from a keyserver"
@@ -2561,6 +2561,9 @@ msgstr ""
 "|DF|escrever informações de estado para o\n"
 "descritor de ficheiro DF"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 #, fuzzy
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Uso: gpg [opções] [ficheiros] (-h para ajuda)"
@@ -4043,6 +4046,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Nenhum ID de utilizador com índice %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "arredondado para %u bits\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4059,11 +4067,6 @@ msgstr "Qual o tamanho de chave desejado? (1024) "
 msgid "Requested keysize is %u bits\n"
 msgstr "O tamanho de chave pedido é %u bits\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "arredondado para %u bits\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5734,14 +5737,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "erro ao enviar para `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "chave pública %08lX não encontrada: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "erro na leitura de `%s': %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5820,14 +5815,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5835,6 +5830,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "erro na leitura de `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "erro na criação da frase secreta: %s\n"
 
@@ -5990,6 +5989,10 @@ msgstr "n
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "não é necessária uma verificação da base de dados de confiança\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "chave pública %08lX não encontrada: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr ""
 
@@ -6068,6 +6071,9 @@ msgstr "vers
 msgid "[  undef ]"
 msgstr ""
 
+msgid "[  never ]"
+msgstr ""
+
 msgid "[marginal]"
 msgstr ""
 
index 79d9bae..9f54576 100644 (file)
--- a/po/ro.po
+++ b/po/ro.po
@@ -475,6 +475,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "eroare trimitere la `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVERTISMENT: permisiuni nesigure (unsafe) pentru extensia `%s'\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "actualizarea a eºuat: %s\n"
 
@@ -493,10 +497,6 @@ msgid "directory '%s' created\n"
 msgstr "director `%s' creat\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "AVERTISMENT: permisiuni nesigure (unsafe) pentru extensia `%s'\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fstat(%d) a eºuat în %s: %s\n"
 
@@ -1954,13 +1954,13 @@ msgstr "schimb
 msgid "export keys"
 msgstr "exportã chei"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exportã chei pentru un server de chei"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importã chei de la un server de chei"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "cautã pentru chei pe un server de chei"
 
 msgid "update all keys from a keyserver"
@@ -2586,6 +2586,9 @@ msgstr "d
 msgid "|FD|write status info to this FD"
 msgstr "|FD|scrie informaþii de stare în acest FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Folosire: gpgv [opþiuni] [fiºiere] (-h pentru ajutor)"
 
@@ -4043,6 +4046,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Nici o subcheie cu indicele %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "rotunjitã prin adaos la %u biþi\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "cheile %s pot avea lungimea între %u ºi %u biþi.\n"
@@ -4059,11 +4067,6 @@ msgstr "Ce lungime de cheie dori
 msgid "Requested keysize is %u bits\n"
 msgstr "Lungimea cheii necesarã este %u biþi\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "rotunjitã prin adaos la %u biþi\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5754,14 +5757,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "eroare trimitere la `%s': %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "cheia publicã %s nu a fost gãsitã: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "eroare la citire `%s': %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5840,14 +5835,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5855,6 +5850,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "eroare la citire `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "eroare la crearea frazei-parolã: %s\n"
 
@@ -6011,6 +6010,10 @@ msgstr "nu e nevoie de o verificare trustdb cu modelul de 
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "nu e nevoie de o actualizare trustdb cu modelul de încredere `%s'\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "cheia publicã %s nu a fost gãsitã: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "vã rugãm faceþi un --check-trustdb\n"
 
@@ -6089,6 +6092,11 @@ msgstr "[necunoscut
 msgid "[  undef ]"
 msgstr "[  nedef ]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "niciodatã"
+
 msgid "[marginal]"
 msgstr "[marginal]"
 
index f311cd1..7997837 100644 (file)
--- a/po/ru.po
+++ b/po/ru.po
@@ -23,7 +23,7 @@ msgstr ""
 
 #, c-format
 msgid "failed to acquire the pinentry lock: %s\n"
-msgstr "сбой при блокировке для ввода PIN: %s\n"
+msgstr "сбой при блокировке для ввода пароля: %s\n"
 
 #. TRANSLATORS: These are labels for buttons etc used in
 #. Pinentries.  An underscore indicates that the next letter
@@ -371,10 +371,9 @@ msgstr "не позволять клиентам помечать ключи к
 msgid "allow presetting passphrase"
 msgstr "разрешить предустанавливать фразу-пароль"
 
-#, fuzzy
-#| msgid "allow caller to override the pinentry"
 msgid "disallow caller to override the pinentry"
-msgstr "разрешить клиентам замещать собой pinentry"
+msgstr ""
+"не позволять вызывающей программе замещать собой программу ввода пароля"
 
 msgid "allow passphrase to be prompted through Emacs"
 msgstr "разрешить ввод фразы-пароля через Emacs"
@@ -444,6 +443,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "ошибка связывания сокета с '%s': %s\n"
 
 #, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "не удалось задать права доступа для '%s': %s\n"
+
+#, c-format
 msgid "listen() failed: %s\n"
 msgstr "сбой listen(): %s\n"
 
@@ -459,11 +462,6 @@ msgstr "не могу создать каталог '%s': %s\n"
 msgid "directory '%s' created\n"
 msgstr "создан каталог '%s'\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Внимание: небезопасные права доступа %s \"%s\"\n"
-
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "сбой stat() для '%s': %s\n"
@@ -678,15 +676,15 @@ msgstr ""
 "Удаление его может лишить Вас возможности доступа к удаленным машинам."
 
 msgid "DSA requires the hash length to be a multiple of 8 bits\n"
-msgstr "DSA требует длины хэша, кратной 8 битам\n"
+msgstr "DSA требует длины хеша, кратной 8 битам\n"
 
 #, c-format
 msgid "%s key uses an unsafe (%u bit) hash\n"
-msgstr "%s ключ использует небезопасный (%u бит) хэш\n"
+msgstr "%s ключ использует небезопасный (%u бит) хеш\n"
 
 #, c-format
 msgid "a %zu bit hash is not valid for a %u bit %s key\n"
-msgstr "%zu-битный хэш недопустим для %u-битного ключа %s\n"
+msgstr "%zu-битный хеш недопустим для %u-битного ключа %s\n"
 
 #, c-format
 msgid "checking created signature failed: %s\n"
@@ -705,7 +703,7 @@ msgstr "алгоритм защиты %d (%s) не поддерживается\
 
 #, c-format
 msgid "protection hash algorithm %d (%s) is not supported\n"
-msgstr "хэш-функция защиты %d (%s) не поддерживается\n"
+msgstr "хеш-функция защиты %d (%s) не поддерживается\n"
 
 #, c-format
 msgid "error creating a pipe: %s\n"
@@ -719,10 +717,9 @@ msgstr "ошибка при создании потока для канала к
 msgid "error forking process: %s\n"
 msgstr "ошибка при дублировании процесса: %s\n"
 
-#, fuzzy, c-format
-#| msgid "waiting for process %d to terminate failed: %s\n"
+#, c-format
 msgid "waiting for processes to terminate failed: %s\n"
-msgstr "сбой при ожидании завершения процесса %d: %s\n"
+msgstr "сбой при ожидании завершения процесса: %s\n"
 
 #, c-format
 msgid "error running '%s': probably not installed\n"
@@ -760,10 +757,9 @@ msgstr "прервано пользователем\n"
 msgid "problem with the agent\n"
 msgstr "проблема с агентом\n"
 
-#, fuzzy, c-format
-#| msgid "problem with the agent: %s\n"
+#, c-format
 msgid "problem with the agent (unexpected response \"%s\")\n"
-msgstr "проблема с агентом: %s\n"
+msgstr "проблема с агентом (неожиданный ответ \"%s\")\n"
 
 #, c-format
 msgid "can't disable core dumps: %s\n"
@@ -931,7 +927,7 @@ msgstr "Данные успешно подписаны"
 
 #, c-format
 msgid "data hash algorithm: %s"
-msgstr "хэш-функция данных: %s"
+msgstr "хеш-функция данных: %s"
 
 #, c-format
 msgid "Signer %d"
@@ -939,7 +935,7 @@ msgstr "Подпись %d"
 
 #, c-format
 msgid "attr hash algorithm: %s"
-msgstr "хэш-функция атрибутов: %s"
+msgstr "хеш-функция атрибутов: %s"
 
 msgid "Data decryption succeeded"
 msgstr "Данные успешно расшифрованы"
@@ -958,7 +954,7 @@ msgstr "Разбор данных завершен"
 
 #, c-format
 msgid "bad data hash algorithm: %s"
-msgstr "недопустимая хэш-функция данных: %s"
+msgstr "недопустимая хеш-функция данных: %s"
 
 #, c-format
 msgid "Signature %d"
@@ -1162,45 +1158,34 @@ msgstr ""
 "символ quoted printable в текстовом формате - испорчено почтовой "
 "программой?\n"
 
-#, fuzzy, c-format
-#| msgid "not human readable"
+#, c-format
 msgid "[ not human readable (%zu bytes: %s%s) ]"
-msgstr "не для чтения человеком"
+msgstr "[ не для чтения человеком (%zu байт: %s%s) ]"
 
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
 msgstr ""
-"имÑ\8f Ð¿Ñ\80имечания должно содержать только печатные символы или пробелы и "
+"имÑ\8f Ð·Ð°мечания должно содержать только печатные символы или пробелы и "
 "заканчиваться знаком '='\n"
 
 msgid "a user notation name must contain the '@' character\n"
-msgstr "имÑ\8f Ð¿Ñ\80имеÑ\87аниÑ\8f Ð¿Ð¾Ð»Ñ\8cзоваÑ\82еля должно содержать символ '@'\n"
+msgstr "имÑ\8f Ð·Ð°Ð¼ÐµÑ\87ания должно содержать символ '@'\n"
 
 msgid "a notation name must not contain more than one '@' character\n"
-msgstr ""
-"имя примечания пользователя не должно содержать более одного символа '@'\n"
+msgstr "имя замечания не должно содержать более одного символа '@'\n"
 
 msgid "a notation value must not use any control characters\n"
-msgstr "в значении примечания не должно быть управляющих символов\n"
+msgstr "в тексте замечания не должно быть управляющих символов\n"
 
-#, fuzzy
-#| msgid "a notation name must not contain more than one '@' character\n"
 msgid "a notation name may not contain an '=' character\n"
-msgstr ""
-"имя примечания пользователя не должно содержать более одного символа '@'\n"
+msgstr "имя примечания не должно содержать символа '='\n"
 
-#, fuzzy
-#| msgid ""
-#| "a notation name must have only printable characters or spaces, and end "
-#| "with an '='\n"
 msgid "a notation name must have only printable characters or spaces\n"
-msgstr ""
-"имя примечания должно содержать только печатные символы или пробелы и "
-"заканчиваться знаком '='\n"
+msgstr "имя замечания должно содержать только печатные символы или пробелы\n"
 
 msgid "WARNING: invalid notation data found\n"
-msgstr "Ð\92нимание: Ð½Ð°Ð¹Ð´ÐµÐ½Ð° Ð½ÐµÐ´Ð¾Ð¿Ñ\83Ñ\81Ñ\82имаÑ\8f Ñ\84оÑ\80ма Ð·Ð°Ð¿Ð¸Ñ\81и Ð¿Ñ\80имечания\n"
+msgstr "Ð\92нимание: Ð½Ð°Ð¹Ð´ÐµÐ½Ð° Ð½ÐµÐ´Ð¾Ð¿Ñ\83Ñ\81Ñ\82имаÑ\8f Ñ\84оÑ\80ма Ð·Ð°Ð¿Ð¸Ñ\81и Ð·Ð°мечания\n"
 
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
@@ -1836,13 +1821,13 @@ msgstr "сменить фразу-пароль"
 msgid "export keys"
 msgstr "экспортировать ключи"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "экспортировать ключи на сервер ключей"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "импортировать ключи с сервера ключей"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "искать ключи на сервере ключей"
 
 msgid "update all keys from a keyserver"
@@ -1864,17 +1849,13 @@ msgid "update the trust database"
 msgstr "обновить таблицу доверия"
 
 msgid "print message digests"
-msgstr "вывести хэши сообщений"
+msgstr "вывести хеши сообщений"
 
 msgid "run in server mode"
 msgstr "запуск в режиме сервера"
 
-#, fuzzy
-#| msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
 msgid "|VALUE|set the TOFU policy for a key"
-msgstr ""
-"|VALUE|установить правила TOFU для ключа (good - хороший, unknown - "
-"неизвестно, bad - плохой, ask - спрашивать, auto - автоматически)"
+msgstr "|VALUE|установить правила TOFU для ключа"
 
 msgid "create ascii armored output"
 msgstr "вывод в текстовом формате"
@@ -1955,7 +1936,7 @@ msgid "Cipher: "
 msgstr "Симметричные шифры: "
 
 msgid "Hash: "
-msgstr "Хэш-функции: "
+msgstr "Хеш-функции: "
 
 msgid "Compression: "
 msgstr "Алгоритмы сжатия: "
@@ -2045,13 +2026,13 @@ msgid "show policy URLs during signature listings"
 msgstr "показать в списке подписей URL правил"
 
 msgid "show all notations during signature listings"
-msgstr "показаÑ\82Ñ\8c Ð² Ñ\81пиÑ\81ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð²Ñ\81е Ð¿Ñ\80имечания"
+msgstr "показаÑ\82Ñ\8c Ð² Ñ\81пиÑ\81ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð²Ñ\81е Ð·Ð°мечания"
 
 msgid "show IETF standard notations during signature listings"
-msgstr "показаÑ\82Ñ\8c Ð² Ñ\81пиÑ\81ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¿Ñ\80имечания стандарта IETF"
+msgstr "показаÑ\82Ñ\8c Ð² Ñ\81пиÑ\81ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð·Ð°мечания стандарта IETF"
 
 msgid "show user-supplied notations during signature listings"
-msgstr "показаÑ\82Ñ\8c Ð² Ñ\81пиÑ\81ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8cÑ\81кие Ð¿Ñ\80имечания"
+msgstr "показаÑ\82Ñ\8c Ð² Ñ\81пиÑ\81ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8cÑ\81кие Ð·Ð°мечания"
 
 msgid "show preferred keyserver URLs during signature listings"
 msgstr "показать в списке подписей URL предпочтительных серверов ключей"
@@ -2103,7 +2084,7 @@ msgstr "'%s' - не допустимый срок действия подпис
 
 #, c-format
 msgid "invalid pinentry mode '%s'\n"
-msgstr "недопустимый режим ввода PIN '%s'\n"
+msgstr "недопустимый режим ввода пароля '%s'\n"
 
 #, c-format
 msgid "'%s' is not a valid character set\n"
@@ -2147,13 +2128,13 @@ msgid "show policy URLs during signature verification"
 msgstr "показать при проверке подписи URL правил"
 
 msgid "show all notations during signature verification"
-msgstr "показаÑ\82Ñ\8c Ð¿Ñ\80и Ð¿Ñ\80овеÑ\80ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð²Ñ\81е Ð¿Ñ\80имечания"
+msgstr "показаÑ\82Ñ\8c Ð¿Ñ\80и Ð¿Ñ\80овеÑ\80ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð²Ñ\81е Ð·Ð°мечания"
 
 msgid "show IETF standard notations during signature verification"
-msgstr "показаÑ\82Ñ\8c Ð¿Ñ\80и Ð¿Ñ\80овеÑ\80ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¿Ñ\80имечания стандарта IETF"
+msgstr "показаÑ\82Ñ\8c Ð¿Ñ\80и Ð¿Ñ\80овеÑ\80ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð·Ð°мечания стандарта IETF"
 
 msgid "show user-supplied notations during signature verification"
-msgstr "показаÑ\82Ñ\8c Ð¿Ñ\80и Ð¿Ñ\80овеÑ\80ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8cÑ\81кие Ð¿Ñ\80имечания"
+msgstr "показаÑ\82Ñ\8c Ð¿Ñ\80и Ð¿Ñ\80овеÑ\80ке Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8cÑ\81кие Ð·Ð°мечания"
 
 msgid "show preferred keyserver URLs during signature verification"
 msgstr "показать при проверке подписей URL предпочтительных серверов ключей"
@@ -2218,13 +2199,13 @@ msgid "selected cipher algorithm is invalid\n"
 msgstr "выбран недопустимый алгоритм шифрования\n"
 
 msgid "selected digest algorithm is invalid\n"
-msgstr "выбрана недопустимая хэш-функция\n"
+msgstr "выбрана недопустимая хеш-функция\n"
 
 msgid "selected compression algorithm is invalid\n"
 msgstr "выбран недопустимый алгоритм сжатия\n"
 
 msgid "selected certification digest algorithm is invalid\n"
-msgstr "выбрана недопустимая хэш-функция для сертификации\n"
+msgstr "выбрана недопустимая хеш-функция для сертификации\n"
 
 msgid "completes-needed must be greater than 0\n"
 msgstr "completes-needed должен быть больше 0\n"
@@ -2254,7 +2235,7 @@ msgid "invalid personal cipher preferences\n"
 msgstr "недопустимые личные предпочтения шифра\n"
 
 msgid "invalid personal digest preferences\n"
-msgstr "недопустимые личные предпочтения хэш-функции\n"
+msgstr "недопустимые личные предпочтения хеш-функции\n"
 
 msgid "invalid personal compress preferences\n"
 msgstr "недопустимые личные предпочтения алгоритмов сжатия\n"
@@ -2269,7 +2250,7 @@ msgstr "шифрование '%s' в режиме %s использовать н
 
 #, c-format
 msgid "you may not use digest algorithm '%s' while in %s mode\n"
-msgstr "хэш-функцию '%s' в режиме %s использовать нельзя\n"
+msgstr "хеш-функцию '%s' в режиме %s использовать нельзя\n"
 
 #, c-format
 msgid "you may not use compression algorithm '%s' while in %s mode\n"
@@ -2379,7 +2360,7 @@ msgstr "ошибка преобразования в текстовый форм
 
 #, c-format
 msgid "invalid hash algorithm '%s'\n"
-msgstr "недопустимая хэш-функция '%s'\n"
+msgstr "недопустимая хеш-функция '%s'\n"
 
 #, c-format
 msgid "error parsing key specification '%s': %s\n"
@@ -2413,6 +2394,9 @@ msgstr "при несоответствии метки времени - толь
 msgid "|FD|write status info to this FD"
 msgstr "|FD|выводить информацию в файл с дескриптором FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Вызов: gpgv [параметры] [файлы] (-h для подсказки)"
 
@@ -2537,7 +2521,7 @@ msgstr "         \"%s\": предпочитает шифр %s\n"
 
 #, c-format
 msgid "         \"%s\": preference for digest algorithm %s\n"
-msgstr "         \"%s\": предпочитает хэш-функцию %s\n"
+msgstr "         \"%s\": предпочитает хеш-функцию %s\n"
 
 #, c-format
 msgid "         \"%s\": preference for compression algorithm %s\n"
@@ -2838,35 +2822,30 @@ msgstr "[отзыв]"
 msgid "[self-signature]"
 msgstr "[самоподпись]"
 
-#, fuzzy, c-format
-#| msgid "key %s: unsupported public key algorithm\n"
+#, c-format
 msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
-msgstr "ключ %s: алгоритм с открытым ключом не поддерживается\n"
+msgstr ""
+"не удалось проверить подпись: алгоритм с открытым ключом %d не "
+"поддерживается: %s.\n"
 
-#, fuzzy, c-format
-#| msgid "card does not support digest algorithm %s\n"
+#, c-format
 msgid ""
 "can't check signature with unsupported message-digest algorithm %d: %s.\n"
-msgstr "каÑ\80Ñ\82а Ð½Ðµ Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82 Ñ\85Ñ\8dÑ\88\84Ñ\83нкÑ\86иÑ\8e %s\n"
+msgstr "не Ñ\83далоÑ\81Ñ\8c Ð¿Ñ\80овеÑ\80иÑ\82Ñ\8c Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c: Ñ\85еÑ\88\84Ñ\83нкÑ\86иÑ\8f %d Ð½Ðµ Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82Ñ\81Ñ\8f: %s.\n"
 
-#, fuzzy
-#| msgid "Good signature from"
 msgid " (reordered signatures follow)"
-msgstr "Хорошая подпись пользователя"
+msgstr "(порядок подписей изменен)"
 
-#, fuzzy, c-format
-#| msgid "key %s: %s\n"
+#, c-format
 msgid "key %s:\n"
-msgstr "ключ %s: %s\n"
+msgstr "ключ %s:\n"
 
-#, fuzzy, c-format
-#| msgid "User ID \"%s\": %d signature removed\n"
-#| msgid_plural "User ID \"%s\": %d signatures removed\n"
+#, c-format
 msgid "%d duplicate signature removed\n"
 msgid_plural "%d duplicate signatures removed\n"
-msgstr[0] "ID пользователя \"%s\": %d подпись удалена\n"
-msgstr[1] "ID пользователя \"%s\": %d подписи удалены\n"
-msgstr[2] "ID пользователя \"%s\": %d подписей удалено\n"
+msgstr[0] "%d повторная подпись удалена\n"
+msgstr[1] "%d повторные подписи удалены\n"
+msgstr[2] "%d повторных подписей удалено\n"
 
 #, c-format
 msgid "%d signature not checked due to a missing key\n"
@@ -2882,19 +2861,20 @@ msgstr[0] "%d плохая подпись\n"
 msgstr[1] "%d плохих подписи\n"
 msgstr[2] "%d плохих подписей\n"
 
-#, fuzzy, c-format
-#| msgid "Good signature from"
+#, c-format
 msgid "%d signature reordered\n"
 msgid_plural "%d signatures reordered\n"
-msgstr[0] "ХоÑ\80оÑ\88аÑ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f"
-msgstr[1] "ХоÑ\80оÑ\88аÑ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f"
-msgstr[2] "ХоÑ\80оÑ\88аÑ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f"
+msgstr[0] "Ð\9fоÑ\80Ñ\8fдок %d Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81и Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½\n"
+msgstr[1] "Ð\9fоÑ\80Ñ\8fдок %d Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½\n"
+msgstr[2] "Ð\9fоÑ\80Ñ\8fдок %d Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½\n"
 
 #, c-format
 msgid ""
 "Warning: errors found and only checked self-signatures, run '%s' to check "
 "all signatures.\n"
 msgstr ""
+"Внимание: обнаружены ошибки, проверялись только самоподписи; для проверки "
+"всех подписей выполните '%s'.\n"
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3174,7 +3154,7 @@ msgstr ""
 "установить URL предпочтительного сервера ключей для выбранных ID пользователя"
 
 msgid "set a notation for the selected user IDs"
-msgstr "Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c Ð¿Ñ\80имечание для выбранных ID пользователя"
+msgstr "Ñ\83Ñ\81Ñ\82ановиÑ\82Ñ\8c Ð·Ð°мечание для выбранных ID пользователя"
 
 msgid "change the passphrase"
 msgstr "сменить фразу-пароль"
@@ -3338,10 +3318,9 @@ msgstr "\"%s\" - не отпечаток\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "\"%s\" - не первичный отпечаток\n"
 
-#, fuzzy, c-format
-#| msgid "invalid value\n"
+#, c-format
 msgid "Invalid user ID '%s': %s\n"
-msgstr "недопÑ\83Ñ\81Ñ\82имое Ð·Ð½Ð°Ñ\87ение\n"
+msgstr "Ð\9dедопÑ\83Ñ\81Ñ\82имÑ\8bй ID Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f '%s': %s\n"
 
 msgid "No matching user IDs."
 msgstr "Нет подходящих ID пользователей."
@@ -3350,7 +3329,7 @@ msgid "Nothing to sign.\n"
 msgstr "Подписывать нечего.\n"
 
 msgid "Digest: "
-msgstr "Хэш: "
+msgstr "Хеш: "
 
 msgid "Features: "
 msgstr "Характеристики: "
@@ -3362,7 +3341,7 @@ msgid "Preferred keyserver: "
 msgstr "Предпочтительный сервер ключей: "
 
 msgid "Notations: "
-msgstr "Ð\9fÑ\80имечания: "
+msgstr "Ð\97амечания: "
 
 msgid "There are no preferences on a PGP 2.x-style user ID.\n"
 msgstr "В ID пользователя типа PGP 2.x не может быть предпочтений.\n"
@@ -3575,7 +3554,7 @@ msgid "Are you sure you want to delete it? (y/N) "
 msgstr "Вы действительно хотите удалить его? (y/N) "
 
 msgid "Enter the notation: "
-msgstr "Ð\92ведиÑ\82е Ð¿Ñ\80имечание: "
+msgstr "Ð\92ведиÑ\82е Ð·Ð°мечание: "
 
 msgid "Proceed? (y/N) "
 msgstr "Продолжить? (y/N) "
@@ -3586,7 +3565,7 @@ msgstr "Нет ID пользователя с индексом %d\n"
 
 #, c-format
 msgid "No user ID with hash %s\n"
-msgstr "Нет ID пользователя с хэшем %s\n"
+msgstr "Нет ID пользователя с хешем %s\n"
 
 #, c-format
 msgid "No subkey with key ID '%s'.\n"
@@ -3668,7 +3647,7 @@ msgid "too many cipher preferences\n"
 msgstr "слишком много шифровых предпочтений\n"
 
 msgid "too many digest preferences\n"
-msgstr "слишком много предпочтений для хэш-функций\n"
+msgstr "слишком много предпочтений для хеш-функций\n"
 
 msgid "too many compression preferences\n"
 msgstr "слишком много предпочтений для методов сжатия\n"
@@ -3698,7 +3677,7 @@ msgid ""
 "WARNING: some OpenPGP programs can't handle a DSA key with this digest size\n"
 msgstr ""
 "Внимание: некоторые реализации OpenPGP не могут обрабатывать ключи DSA с "
-"такой длиной хэша\n"
+"такой длиной хеша\n"
 
 msgid "Sign"
 msgstr "Подписать"
@@ -3813,6 +3792,10 @@ msgid "No key with this keygrip\n"
 msgstr "Нет ключа с таким кодом\n"
 
 #, c-format
+msgid "rounded to %u bits\n"
+msgstr "округлен до %u бит\n"
+
+#, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "длина ключей %s может быть от %u до %u бит.\n"
 
@@ -3828,10 +3811,6 @@ msgstr "Какой размер ключа Вам необходим? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Запрошенный размер ключа - %u бит\n"
 
-#, c-format
-msgid "rounded to %u bits\n"
-msgstr "округлен до %u бит\n"
-
 msgid "Please select which elliptic curve you want:\n"
 msgstr "Выберите эллиптическую кривую:\n"
 
@@ -4118,10 +4097,10 @@ msgid "Critical preferred keyserver: "
 msgstr "Критический предпочтительный сервер ключей: "
 
 msgid "Critical signature notation: "
-msgstr "Ð\9aÑ\80иÑ\82иÑ\87еÑ\81кое Ð¿Ñ\80имечание к подписи: "
+msgstr "Ð\9aÑ\80иÑ\82иÑ\87еÑ\81кое Ð·Ð°мечание к подписи: "
 
 msgid "Signature notation: "
-msgstr "Ð\9fÑ\80имечание к подписи: "
+msgstr "Ð\97амечание к подписи: "
 
 #, c-format
 msgid "%d good signature\n"
@@ -4152,7 +4131,7 @@ msgid "skipped \"%s\": %s\n"
 msgstr "пропущено \"%s\": %s\n"
 
 msgid "Primary key fingerprint:"
-msgstr "Ð\9eÑ\82пеÑ\87аÑ\82ок Ð³Ð»Ð°Ð²ного ключа:"
+msgstr "Ð\9eÑ\82пеÑ\87аÑ\82ок Ð¿ÐµÑ\80виÑ\87ного ключа:"
 
 msgid "     Subkey fingerprint:"
 msgstr "      Отпечаток подключа:"
@@ -4160,7 +4139,7 @@ msgstr "      Отпечаток подключа:"
 #. TRANSLATORS: this should fit into 24 bytes so that the
 #. * fingerprint data is properly aligned with the user ID
 msgid " Primary key fingerprint:"
-msgstr " Ð\9eÑ\82пеÑ\87аÑ\82ок Ð³Ð»Ð°Ð²ного ключа:"
+msgstr " Ð\9eÑ\82пеÑ\87аÑ\82ок Ð¿ÐµÑ\80виÑ\87ного ключа:"
 
 msgid "      Subkey fingerprint:"
 msgstr "       Отпечаток подключа:"
@@ -4289,7 +4268,7 @@ msgstr "сеансовый ключ зашифрован по %s\n"
 
 #, c-format
 msgid "passphrase generated with unknown digest algorithm %d\n"
-msgstr "фраза-пароль создана с незнакомой хэш-функцией %d\n"
+msgstr "фраза-пароль создана с незнакомой хеш-функцией %d\n"
 
 #, c-format
 msgid "public key is %s\n"
@@ -4408,7 +4387,7 @@ msgstr "Подпись действительна до %s\n"
 
 #, c-format
 msgid "%s signature, digest algorithm %s%s%s\n"
-msgstr "формат подписи: %s, хэш-функция %s%s%s\n"
+msgstr "формат подписи: %s, хеш-функция %s%s%s\n"
 
 msgid "binary"
 msgstr "двоичный"
@@ -4470,15 +4449,15 @@ msgstr ""
 
 #, c-format
 msgid "WARNING: using experimental digest algorithm %s\n"
-msgstr "Внимание: используется экспериментальная хэш-функция %s\n"
+msgstr "Внимание: используется экспериментальная хеш-функция %s\n"
 
 #, c-format
 msgid "WARNING: digest algorithm %s is deprecated\n"
-msgstr "Внимание: хэш-функция %s не рекомендуется\n"
+msgstr "Внимание: хеш-функция %s не рекомендуется\n"
 
 #, c-format
 msgid "Note: signatures using the %s algorithm are rejected\n"
-msgstr "Замечание: подписи с хэш-функцией %s игнорируются\n"
+msgstr "Замечание: подписи с хеш-функцией %s игнорируются\n"
 
 #, c-format
 msgid "(reported error: %s)\n"
@@ -4541,7 +4520,7 @@ msgstr "Открытый ключ ECDSA бывает в кодировке SEC,
 
 #, c-format
 msgid "unknown weak digest '%s'\n"
-msgstr "неизвестный слабый хэш '%s'\n"
+msgstr "неизвестный слабый хеш '%s'\n"
 
 #, c-format
 msgid "File '%s' exists. "
@@ -5122,14 +5101,14 @@ msgstr ""
 
 #, c-format
 msgid "%s key %s uses an unsafe (%zu bit) hash\n"
-msgstr "ключ %s %s использует небезопасный (%zu-битный) хэш\n"
+msgstr "ключ %s %s использует небезопасный (%zu-битный) хеш\n"
 
 #, c-format
 msgid "%s key %s requires a %zu bit or larger hash (hash is %s)\n"
-msgstr "Ключ %s %s требует %zu-битного или более длинного хэша (хэш %s)\n"
+msgstr "Ключ %s %s требует %zu-битного или более длинного хеша (хеш %s)\n"
 
 msgid "WARNING: signature digest conflict in message\n"
-msgstr "Внимание: конфликт хэшей подписей в сообщении\n"
+msgstr "Внимание: конфликт хешей подписей в сообщении\n"
 
 #, c-format
 msgid "WARNING: signing subkey %s is not cross-certified\n"
@@ -5210,7 +5189,7 @@ msgstr "ключ %s: нет подключа для подписи связи п
 #, c-format
 msgid "WARNING: unable to %%-expand notation (too large).  Using unexpanded.\n"
 msgstr ""
-"Ð\92нимание: Ð½Ðµ Ð¼Ð¾Ð³Ñ\83 Ñ\80азвеÑ\80нÑ\83Ñ\82Ñ\8c %% Ð² Ð¿Ñ\80имечании (слишком длинное).\n"
+"Ð\92нимание: Ð½Ðµ Ð¼Ð¾Ð³Ñ\83 Ñ\80азвеÑ\80нÑ\83Ñ\82Ñ\8c %% Ð² Ð·Ð°мечании (слишком длинное).\n"
 "          Использую неразвернутым.\n"
 
 #, c-format
@@ -5236,7 +5215,7 @@ msgstr "подпись %s/%s пользователя \"%s\"\n"
 msgid ""
 "WARNING: forcing digest algorithm %s (%d) violates recipient preferences\n"
 msgstr ""
-"Внимание: использование хэш-функции %s (%d) нарушает предпочтения "
+"Внимание: использование хеш-функции %s (%d) нарушает предпочтения "
 "получателя\n"
 
 msgid "signing:"
@@ -5350,7 +5329,7 @@ msgstr "%s: недопустимая таблица доверия\n"
 
 #, c-format
 msgid "%s: failed to create hashtable: %s\n"
-msgstr "%s: сбой создания таблицы хэшей: %s\n"
+msgstr "%s: сбой создания таблицы хешей: %s\n"
 
 #, c-format
 msgid "%s: error updating version record: %s\n"
@@ -5454,27 +5433,16 @@ msgid "error updating TOFU database: %s\n"
 msgstr "ошибка обновления базы данных TOFU: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "открытый ключ %s не найден: %s\n"
-
-#, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "ошибка установки уровня доверия привязки TOFU в %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr "Привязка %s неизвестна."
 
-#, fuzzy, c-format
-#| msgid ""
-#| "The key %s raised a conflict with this binding (%s).  Since this "
-#| "binding's policy was 'auto', it was changed to 'ask'."
+#, c-format
 msgid ""
 "The key with fingerprint %s raised a conflict with the binding %s.  Since "
 "this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
-"Ключ %s противоречит этой привязке (%s). Поскольку правило привязки было "
-"'автоматически', оно изменилось на 'спрашивать'."
+"Ключ с отпечатком %s противоречит этой привязке %s. Поскольку правило "
+"привязки было 'автоматически', оно изменилось на 'спрашивать'."
 
 #, c-format
 msgid ""
@@ -5549,8 +5517,8 @@ msgstr[1] " за %ld прошедших месяца."
 msgstr[2] " за %ld прошедших месяцев."
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 "Обычно с конкретным адресом электронной почты связан только один ключ. "
@@ -5561,8 +5529,8 @@ msgstr ""
 "правомерен."
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr "gGaAuUrRbB"
 
@@ -5571,86 +5539,74 @@ msgstr ""
 "(G)Хороший, (A)Пока принять, (U)Неясно, (R)Пока отвергнуть, (B)Плохой? "
 
 #, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "ошибка установки уровня доверия привязки TOFU в %s\n"
+
+#, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "ошибка при смене правила TOFU: %s\n"
 
 #. TRANSLATORS: The tilde ('~') is used here to indicate a
 #. * non-breakable space
-#, fuzzy, c-format
-#| msgid "%d year"
-#| msgid_plural "%d years"
+#, c-format
 msgid "%d~year"
 msgid_plural "%d~years"
-msgstr[0] "%d год"
-msgstr[1] "%d года"
-msgstr[2] "%d лет"
+msgstr[0] "%d~год"
+msgstr[1] "%d~года"
+msgstr[2] "%d~лет"
 
-#, fuzzy, c-format
-#| msgid "%d month"
-#| msgid_plural "%d months"
+#, c-format
 msgid "%d~month"
 msgid_plural "%d~months"
-msgstr[0] "%d месяц"
-msgstr[1] "%d месяца"
-msgstr[2] "%d месяцев"
+msgstr[0] "%d~месяц"
+msgstr[1] "%d~месяца"
+msgstr[2] "%d~месяцев"
 
 #, c-format
 msgid "%d~day"
 msgid_plural "%d~days"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d~день"
+msgstr[1] "%d~дня"
+msgstr[2] "%d~дней"
 
-#, fuzzy, c-format
-#| msgid "%d hour"
-#| msgid_plural "%d hours"
+#, c-format
 msgid "%d~hour"
 msgid_plural "%d~hours"
-msgstr[0] "%d час"
-msgstr[1] "%d часа"
-msgstr[2] "%d часов"
+msgstr[0] "%d~час"
+msgstr[1] "%d~часа"
+msgstr[2] "%d~часов"
 
-#, fuzzy, c-format
-#| msgid "%d minute"
-#| msgid_plural "%d minutes"
+#, c-format
 msgid "%d~minute"
 msgid_plural "%d~minutes"
-msgstr[0] "%d минута"
-msgstr[1] "%d минуты"
-msgstr[2] "%d минут"
+msgstr[0] "%d~минута"
+msgstr[1] "%d~минуты"
+msgstr[2] "%d~минут"
 
-#, fuzzy, c-format
-#| msgid "%d second"
-#| msgid_plural "%d seconds"
+#, c-format
 msgid "%d~second"
 msgid_plural "%d~seconds"
-msgstr[0] "%d секунда"
-msgstr[1] "%d секунды"
-msgstr[2] "%d секунд"
+msgstr[0] "%d~секунда"
+msgstr[1] "%d~секунды"
+msgstr[2] "%d~секунд"
 
 #, c-format
 msgid "Have never verified a message signed by key %s!\n"
 msgstr "Сообщения, подписанные ключом %s, никогда не проверялись!\n"
 
-#, fuzzy, c-format
-#| msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+#, c-format
 msgid ""
 "Failed to collect signature statistics for \"%s\"\n"
 "(key %s)\n"
-msgstr "Не удалось собрать статистику для \"%s\" (ключ %s)\n"
+msgstr ""
+"Не удалось собрать статистику подписей для \"%s\"\n"
+"(ключ %s)\n"
 
-#, fuzzy, c-format
-#| msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
+#, c-format
 msgid "Verified %ld messages signed by \"%s\"."
-msgstr "Проверено 0 сообщений, подписанных \"%s\" (ключ: %s, правило: %s)."
-
-#, fuzzy, c-format
-#| msgid ""
-#| "Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past "
-#| "%s."
-#| msgid_plural ""
-#| "Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past "
-#| "%s."
+msgstr "Проверено %ld сообщений, подписанных \"%s\"."
+
+#, c-format
 msgid ""
 "Verified %ld message signed by \"%s\"\n"
 "in the past %s."
@@ -5658,11 +5614,14 @@ msgid_plural ""
 "Verified %ld messages signed by \"%s\"\n"
 "in the past %s."
 msgstr[0] ""
-"Проверено %ld сообщение, подписанное \"%s\" (ключ: %s, правило: %s) за %s."
+"Проверено %ld сообщение, подписанное \"%s\"\n"
+" за %s."
 msgstr[1] ""
-"Проверены %ld сообщения, подписанные \"%s\" (ключ: %s, правило: %s) за %s."
+"Проверены %ld сообщения, подписанные \"%s\"\n"
+" за %s."
 msgstr[2] ""
-"Проверено %ld сообщений, подписанных \"%s\" (ключ: %s, правило: %s) за %s."
+"Проверено %ld сообщений, подписанных \"%s\"\n"
+" за %s."
 
 #, c-format
 msgid "The most recent message was verified %s ago."
@@ -5692,8 +5651,23 @@ msgid_plural ""
 "  %s\n"
 "to mark it as being bad.\n"
 msgstr[0] ""
+"Внимание: если вы видели больше %ld сообщения, подписанного этим ключом, "
+"этот ключ может быть подделкой! Внимательно проверьте, не внесены ли в адрес "
+"электронной почты небольшие изменения. В случае подозрений пометьте ключ как "
+"некачественный командой\n"
+"  %s\n"
 msgstr[1] ""
+"Внимание: если вы видели больше %ld сообщений, подписанных этим ключом, этот "
+"ключ может быть подделкой! Внимательно проверьте, не внесены ли в адрес "
+"электронной почты небольшие изменения. В случае подозрений пометьте ключ как "
+"некачественный командой\n"
+"  %s\n"
 msgstr[2] ""
+"Внимание: если вы видели больше %ld сообщений, подписанных этим ключом, этот "
+"ключ может быть подделкой! Внимательно проверьте, не внесены ли в адрес "
+"электронной почты небольшие изменения. В случае подозрений пометьте ключ как "
+"некачественный командой\n"
+"  %s\n"
 
 #, c-format
 msgid "error opening TOFU database: %s\n"
@@ -5757,6 +5731,10 @@ msgstr "проверять таблицу доверия при модели д
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "обновлять таблицу доверия при модели доверия '%s' не нужно\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "открытый ключ %s не найден: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "выполните --check-trustdb, пожалуйста\n"
 
@@ -5834,6 +5812,11 @@ msgstr "[ неизвестно ]"
 msgid "[  undef ]"
 msgstr "[неопределено]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "никогда"
+
 msgid "[marginal]"
 msgstr "[ ограничено ]"
 
@@ -6083,7 +6066,7 @@ msgstr "отпечаток на карте не совпадает с запро
 
 #, c-format
 msgid "card does not support digest algorithm %s\n"
-msgstr "карта не поддерживает хэш-функцию %s\n"
+msgstr "карта не поддерживает хеш-функцию %s\n"
 
 #, c-format
 msgid "signatures created so far: %lu\n"
@@ -6350,7 +6333,7 @@ msgstr "используется схема проверки: %s"
 
 #, c-format
 msgid "a %u bit hash is not valid for a %u bit %s key\n"
-msgstr "%u-битный хэш недопустим для %u-битного ключа %s\n"
+msgstr "%u-битный хеш недопустим для %u-битного ключа %s\n"
 
 msgid "(this is the MD2 algorithm)\n"
 msgstr "(это алгоритм MD2)\n"
@@ -6454,7 +6437,7 @@ msgstr "строка %d: ошибка получения кода подписы
 
 #, c-format
 msgid "line %d: invalid hash algorithm given\n"
-msgstr "строка %d: задана недопустимая хэш-функция\n"
+msgstr "строка %d: задана недопустимая хеш-функция\n"
 
 #, c-format
 msgid "line %d: invalid authority-key-id\n"
@@ -6699,7 +6682,7 @@ msgid "|NAME|use cipher algorithm NAME"
 msgstr "|NAME|использовать алгоритм шифрования NAME"
 
 msgid "|NAME|use message digest algorithm NAME"
-msgstr "|NAME|использовать хэш-функцию NAME"
+msgstr "|NAME|использовать хеш-функцию NAME"
 
 msgid "Usage: @GPGSM@ [options] [files] (-h for help)"
 msgstr "Вызов: @GPGSM@ [параметры] [файлы] (-h для подсказки)"
@@ -6844,11 +6827,11 @@ msgstr ""
 
 #, c-format
 msgid "hash algorithm %d (%s) for signer %d not supported; using %s\n"
-msgstr "хэш-функция %d (%s) для %d не поддерживается; использую %s\n"
+msgstr "хеш-функция %d (%s) для %d не поддерживается; использую %s\n"
 
 #, c-format
 msgid "hash algorithm used for signer %d: %s (%s)\n"
-msgstr "хэш-функция для подписи %d: %s (%s)\n"
+msgstr "хеш-функция для подписи %d: %s (%s)\n"
 
 #, c-format
 msgid "checking for qualified certificate failed: %s\n"
@@ -6867,7 +6850,7 @@ msgstr " с помощью сертификата с ID 0x%08lX\n"
 msgid ""
 "invalid signature: message digest attribute does not match computed one\n"
 msgstr ""
-"недопустимая подпись: атрибут хэш-функции сообщения не соответствует "
+"недопустимая подпись: атрибут хеш-функции сообщения не соответствует "
 "вычисленному\n"
 
 msgid "Good signature from"
@@ -7050,7 +7033,7 @@ msgstr "запись неподдерживаемого типа в '%s', стр
 
 #, c-format
 msgid "invalid issuer hash in '%s' line %u\n"
-msgstr "неправильный хэш издателя в '%s', строка %u\n"
+msgstr "неправильный хеш издателя в '%s', строка %u\n"
 
 #, c-format
 msgid "no issuer DN in '%s' line %u\n"
@@ -7062,7 +7045,7 @@ msgstr "недопустимая метка времени в '%s', строка
 
 #, c-format
 msgid "WARNING: invalid cache file hash in '%s' line %u\n"
-msgstr "Внимание: недопустимый хэш файла буфера в '%s', строка %u\n"
+msgstr "Внимание: недопустимый хеш файла буфера в '%s', строка %u\n"
 
 msgid "detected errors in cache dir file\n"
 msgstr "в файле каталога буфера обнаружены ошибки\n"
@@ -7084,15 +7067,15 @@ msgstr "ошибка переименования '%s' в '%s': %s\n"
 
 #, c-format
 msgid "can't hash '%s': %s\n"
-msgstr "невозможно получить хэш '%s': %s\n"
+msgstr "невозможно получить хеш '%s': %s\n"
 
 #, c-format
 msgid "error setting up MD5 hash context: %s\n"
-msgstr "ошибка установки контекста хэша MD5: %s\n"
+msgstr "ошибка установки контекста хеша MD5: %s\n"
 
 #, c-format
 msgid "error hashing '%s': %s\n"
-msgstr "ошибка при получении хэша '%s': %s\n"
+msgstr "ошибка при получении хеша '%s': %s\n"
 
 #, c-format
 msgid "invalid formatted checksum for '%s'\n"
@@ -7181,7 +7164,7 @@ msgstr "ошибка получения данных из файла буфер
 
 #, c-format
 msgid "unknown hash algorithm '%s'\n"
-msgstr "недопустимая хэш-функция '%s'\n"
+msgstr "недопустимая хеш-функция '%s'\n"
 
 #, c-format
 msgid "gcry_md_open for algorithm %d failed: %s\n"
@@ -7922,7 +7905,7 @@ msgstr "статус ответчика OCSP на '%s': %s\n"
 
 #, c-format
 msgid "hashing the OCSP response for '%s' failed: %s\n"
-msgstr "сбой получения хэша ответа OCSP для '%s': %s\n"
+msgstr "сбой получения хеша ответа OCSP для '%s': %s\n"
 
 msgid "not signed by a default OCSP signer's certificate"
 msgstr "не подписано основным сертификатом подписывающего OCSP"
@@ -7975,7 +7958,7 @@ msgstr "используется ответчик OCSP '%s'\n"
 
 #, c-format
 msgid "failed to establish a hashing context for OCSP: %s\n"
-msgstr "сбой при установлении контекста хэша для OCSP: %s\n"
+msgstr "сбой при установлении контекста хеша для OCSP: %s\n"
 
 #, c-format
 msgid "error getting OCSP status for target certificate: %s\n"
@@ -8086,7 +8069,7 @@ msgid "certificate chain is good\n"
 msgstr "хорошая цепочка сертификатов\n"
 
 msgid "DSA requires the use of a 160 bit hash algorithm\n"
-msgstr "DSA требует 160-битной хэш-функции\n"
+msgstr "DSA требует 160-битной хеш-функции\n"
 
 msgid "certificate should not have been used for CRL signing\n"
 msgstr ""
@@ -8206,7 +8189,7 @@ msgid "do not allow the reuse of old passphrases"
 msgstr "не разрешать повторное использование старых фраз-паролей"
 
 msgid "|N|set the Pinentry timeout to N seconds"
-msgstr "|N|установить время ожидания ввода PIN N секунд"
+msgstr "|N|установить время ожидания ввода пароля N секунд"
 
 msgid "|NAME|use NAME as default secret key"
 msgstr "|NAME|использовать NAME как основной секретный ключ"
@@ -8497,193 +8480,3 @@ msgid ""
 msgstr ""
 "Синтаксис: gpg-check-pattern [параметры] файл_образцов\n"
 "Проверить фразу-пароль, поступающую из stdin, по файлу образцов\n"
-
-#~ msgid "you found a bug ... (%s:%d)\n"
-#~ msgstr "Вы нашли ошибку в программе ... (%s:%d)\n"
-
-#~ msgid "%d user ID without valid self-signature detected\n"
-#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
-#~ msgstr[0] "обнаружен %d ID пользователя без действительной самоподписи\n"
-#~ msgstr[1] "обнаружены %d ID пользователя без действительной самоподписи\n"
-#~ msgstr[2] "обнаружено %d ID пользователя без действительной самоподписи\n"
-
-#~ msgid "moving a key signature to the correct place\n"
-#~ msgstr "перемещение подписи ключа в нужное место\n"
-
-#~ msgid "%d day"
-#~ msgid_plural "%d days"
-#~ msgstr[0] "%d день"
-#~ msgstr[1] "%d дня"
-#~ msgstr[2] "%d дней"
-
-#  I believe the translation produces an equivalent Russian output
-#  for that code snippet in g10/tofu.c -- ineiev
-#~ msgid "TOFU: few signatures %d message %s"
-#~ msgid_plural "TOFU: few signatures %d messages %s"
-#~ msgstr[0] ""
-#~ "Внимание: если Вы думаете, что видели больше %d сообщения, подписанного "
-#~ "этим ключом, то этот ключ может быть подделкой! Проверьте внимательно, не "
-#~ "внесены ли в адрес электронной почты небольшие изменения (напр., "
-#~ "дополнительные пробелы). В случае подозрений отметьте его как плохой с "
-#~ "помощью '%s'.\n"
-#~ " "
-#~ msgstr[1] ""
-#~ "Внимание: если Вы думаете, что видели больше %d сообщений, подписанных "
-#~ "этим ключом, то этот ключ может быть подделкой! Проверьте внимательно, не "
-#~ "внесены ли в адрес электронной почты небольшие изменения (напр., "
-#~ "дополнительные пробелы). В случае подозрений отметьте его как плохой с "
-#~ "помощью '%s'.\n"
-#~ " "
-#~ msgstr[2] ""
-#~ "Внимание: если Вы думаете, что видели больше %d сообщений, подписанных "
-#~ "этим ключом, то этот ключ может быть подделкой! Проверьте внимательно, не "
-#~ "внесены ли в адрес электронной почты небольшие изменения (напр., "
-#~ "дополнительные пробелы). В случае подозрений отметьте его как плохой с "
-#~ "помощью '%s'.\n"
-#~ " "
-
-#~ msgid "key specification '%s' is ambiguous\n"
-#~ msgstr "спецификация ключа '%s' неоднозначна\n"
-
-#~ msgid "'%s' matches at least:\n"
-#~ msgstr "'%s' соответствует по меньшей мере:\n"
-
-#~ msgid "%d signatures not checked due to missing keys\n"
-#~ msgstr "%d подписей не проверено за отсутствием ключей\n"
-
-#~ msgid "%d signatures not checked due to errors\n"
-#~ msgstr "%d подписей не проверено из-за ошибок\n"
-
-#~ msgid "1 user ID without valid self-signature detected\n"
-#~ msgstr "обнаружен 1 ID пользователя без действительной самоподписи\n"
-
-#~ msgid "Deleted %d signatures.\n"
-#~ msgstr "Удалено %d подписей.\n"
-
-#~ msgid "User ID \"%s\": %d signatures removed\n"
-#~ msgstr "ID пользователя \"%s\": %d подписей удалено\n"
-
-#~ msgid ""
-#~ "You need a Passphrase to protect your secret key.\n"
-#~ "\n"
-#~ msgstr ""
-#~ "Для защиты секретного ключа необходима фраза-пароль.\n"
-#~ "\n"
-
-#~ msgid ""
-#~ "Please enter a passphrase to protect the off-card backup of the new "
-#~ "encryption key."
-#~ msgstr ""
-#~ "Введите фразу-пароль для защиты архивной копии нового ключа для "
-#~ "шифрования."
-
-#~ msgid "passphrase not correctly repeated; try again"
-#~ msgstr "фраза-пароль повторена неверно; попробуйте еще раз"
-
-#~ msgid "%s.\n"
-#~ msgstr "%s.\n"
-
-#~ msgid ""
-#~ "You don't want a passphrase - this is probably a *bad* idea!\n"
-#~ "I will do it anyway.  You can change your passphrase at any time,\n"
-#~ "using this program with the option \"--edit-key\".\n"
-#~ "\n"
-#~ msgstr ""
-#~ "Хотите обойтись без фразы-пароля? Скорее всего, это ПЛОХАЯ мысль!\n"
-#~ "Работа будет продолжена. Вы можете сменить фразу-пароль в любое время,\n"
-#~ "запустив данную программу с параметром \"--edit-key\".\n"
-#~ "\n"
-
-#~ msgid "storing key onto card failed: %s\n"
-#~ msgstr "сбой сохранения ключа на карте: %s\n"
-
-#~ msgid "1 good signature\n"
-#~ msgstr "1 хорошая подпись\n"
-
-#~ msgid "renaming '%s' to '%s' failed: %s\n"
-#~ msgstr "сбой при переименовании '%s' в '%s': %s\n"
-
-#~ msgid "%lu keys cached (%lu signatures)\n"
-#~ msgstr "%lu ключей помещено в буфер (%lu подписей)\n"
-
-#~ msgid "refreshing 1 key from %s\n"
-#~ msgstr "обновление 1 ключа из %s\n"
-
-#~ msgid "sending key %s to %s server %s\n"
-#~ msgstr "отправка ключа %s на сервер %s %s\n"
-
-#~ msgid "public key %s is %lu seconds newer than the signature\n"
-#~ msgstr "открытый ключ %s на %lu секунд новее подписи\n"
-
-#~ msgid ""
-#~ "key %s was created %lu seconds in the future (time warp or clock "
-#~ "problem)\n"
-#~ msgstr ""
-#~ "ключ %s создан на %lu секунд в будущем (петля во времени или проблемы с "
-#~ "часами)\n"
-
-#~ msgid "%d marginal(s) needed, %d complete(s) needed, %s trust model\n"
-#~ msgstr ""
-#~ "требуется %d с ограниченным доверием, %d с полным, модель доверия %s\n"
-
-#~ msgid "cleared passphrase cached with ID: %s\n"
-#~ msgstr "в буфере сброшена фраза-пароль с индексом %s\n"
-
-#, fuzzy
-#~| msgid "failed to store the key: %s\n"
-#~ msgid "Failed to open the keyring DB.\n"
-#~ msgstr "сбой сохранения ключа: %s\n"
-
-#, fuzzy
-#~| msgid "failed to open '%s': %s\n"
-#~ msgid "Failed to parse '%s'.\n"
-#~ msgstr "не могу открыть '%s': %s\n"
-
-#, fuzzy
-#~| msgid "error locking keybox: %s\n"
-#~ msgid "error looking up secret key \"%s\": %s\n"
-#~ msgstr "ошибка блокировки щита с ключами: %s\n"
-
-#~ msgid "Please select at most one subkey.\n"
-#~ msgstr "Выделите не более одного подключа.\n"
-
-#~ msgid "apparently no running dirmngr\n"
-#~ msgstr "видимо, dirmngr не работает\n"
-
-#~ msgid "no running dirmngr - starting one\n"
-#~ msgstr "dirmngr не выполняется - запуск\n"
-
-#~ msgid "malformed %s environment variable\n"
-#~ msgstr "неправильная переменная окружения %s\n"
-
-#~ msgid "dirmngr protocol version %d is not supported\n"
-#~ msgstr "протокол dirmngr версии %d не поддерживается\n"
-
-#~ msgid "can't connect to the dirmngr - trying fall back\n"
-#~ msgstr "не могу подключиться к dirmngr - пробую запасной вариант\n"
-
-#~ msgid "export keys in an S-expression based format"
-#~ msgstr "экспортировать ключи в формате на основе S-выражений"
-
-#~ msgid "Directory Manager"
-#~ msgstr "Управление каталогами"
-
-#~ msgid "toggle between the secret and public key listings"
-#~ msgstr "переключение между просмотром открытых и закрытых ключей"
-
-#~ msgid "Please use the command \"toggle\" first.\n"
-#~ msgstr "Сначала воспользуйтесь командой \"toggle\".\n"
-
-#~ msgid "Passphrase"
-#~ msgstr "Фраза-пароль"
-
-#~ msgid "use temporary files to pass data to keyserver helpers"
-#~ msgstr "передавать данные в сервер с помощью временных файлов"
-
-#~ msgid "do not delete temporary files after using them"
-#~ msgstr "не удалять временные файлы после использования"
-
-#~ msgid "WARNING: keyserver option '%s' is not used on this platform\n"
-#~ msgstr ""
-#~ "ВНИМАНИЕ: параметр сервера ключей `%s' на данной платформе не "
-#~ "используется\n"
index 3bf2c2b..bf23106 100644 (file)
--- a/po/sk.po
+++ b/po/sk.po
@@ -465,6 +465,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "chyba pri posielaní na `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "VAROVANIE: prístupové práva pre %s nie sú nastavené bezpeène \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "aktualizácia zlyhala: %s\n"
 
@@ -482,10 +486,6 @@ msgid "directory '%s' created\n"
 msgstr "%s: adresár vytvorený\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "VAROVANIE: prístupové práva pre %s nie sú nastavené bezpeène \"%s\"\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "databáza dôvery: procedúra read() (n=%d) zlyhala: %s\n"
 
@@ -1960,13 +1960,13 @@ msgstr "zmeni
 msgid "export keys"
 msgstr "exportova» kµúèe"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exportova» kµúèe na server kµúèov"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importova» kµúèe zo servera kµúèov"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "vyhµada» kµúèe na serveri kµúèov"
 
 msgid "update all keys from a keyserver"
@@ -2571,6 +2571,9 @@ msgstr "konflikt 
 msgid "|FD|write status info to this FD"
 msgstr "|FD|zapísa» informácie o stave do tohto FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Pou¾itie: gpgv [mo¾nosti] [súbory] (-h pre pomoc)"
 
@@ -4053,6 +4056,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "Neexistuje identifikátor u¾ívateµa s indexom %d\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "zaokrúhlené na %u bitov\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr ""
@@ -4069,11 +4077,6 @@ msgstr "Ak
 msgid "Requested keysize is %u bits\n"
 msgstr "Po¾adovaná då¾ka kµúèa je %u bitov.\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "zaokrúhlené na %u bitov\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5749,14 +5752,6 @@ msgstr ""
 msgid "error updating TOFU database: %s\n"
 msgstr "chyba pri posielaní na `%s': %s\n"
 
-#, fuzzy, c-format
-msgid "public key %s not found: %s\n"
-msgstr "verejný kµúè %08lX nebol nájdený: %s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "chyba pri èítaní `%s': %s\n"
-
 #, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
@@ -5835,14 +5830,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5850,6 +5845,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "chyba pri èítaní `%s': %s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "chyba pri vytváraní hesla: %s\n"
 
@@ -6004,6 +6003,10 @@ msgstr "nie je nutn
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "nie je nutné kontrolova» databázu dôvery\n"
 
+#, fuzzy, c-format
+msgid "public key %s not found: %s\n"
+msgstr "verejný kµúè %08lX nebol nájdený: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "prosím vykonajte --check-trustdb\n"
 
@@ -6081,6 +6084,10 @@ msgstr "nezn
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+msgid "[  never ]"
+msgstr "nikdy     "
+
 msgid "[marginal]"
 msgstr ""
 
index a88dd81..996912a 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -516,6 +516,12 @@ msgstr "fel vid hämtning av nonce för uttaget\n"
 msgid "error binding socket to '%s': %s\n"
 msgstr "fel när \"%s\" bands till uttag: %s\n"
 
+# Extension är vad? FIXME
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Varning: osäkra rättigheter på %s \"%s\"\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "listen() misslyckades: %s\n"
@@ -535,12 +541,6 @@ msgstr "%s: kan inte skapa katalog: %s\n"
 msgid "directory '%s' created\n"
 msgstr "katalogen \"%s\" skapades\n"
 
-# Extension är vad? FIXME
-#, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Varning: osäkra rättigheter på %s \"%s\"\n"
-
 #, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
@@ -2019,13 +2019,13 @@ msgstr "ändra en lösenfras"
 msgid "export keys"
 msgstr "exportera nycklar"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "exportera nycklar till en nyckelserver"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "importera nycklar från en nyckelserver"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "sök efter nycklar hos en nyckelserver"
 
 msgid "update all keys from a keyserver"
@@ -2652,6 +2652,9 @@ msgstr "utfärda enbart en varning när tidsstämpeln är orimlig"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|skriv statusinformation till denna FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Användning: gpgv [flaggor] [filer] (-h för hjälp)"
 
@@ -4129,6 +4132,11 @@ msgstr "Inte en giltig nyckelhash (förväntade 40 hexadecimala siffror)\n"
 msgid "No key with this keygrip\n"
 msgstr "Ingen nyckel med denna nyckelhash\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "avrundade uppåt till %u bitar\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "%s-nycklar kan vara mellan %u och %u bitar långa.\n"
@@ -4145,11 +4153,6 @@ msgstr "Vilken nyckelstorlek vill du ha? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Den efterfrågade nyckelstorleken är %u bitar\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "avrundade uppåt till %u bitar\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5882,15 +5885,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "fel vid sändning av %s-kommando: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "publika nyckeln %s hittades inte: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error storing flags: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "fel vid lagring av flaggor: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5971,14 +5965,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5986,6 +5980,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error storing flags: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "fel vid lagring av flaggor: %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "fel när ett rör skapades: %s\n"
@@ -6151,6 +6150,10 @@ msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr ""
 "det behövs ingen uppdatering av tillitsdatabasen med tillitsmodellen \"%s\"\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "publika nyckeln %s hittades inte: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "gör en kontroll av tillitsdatabasen --check-trustdb\n"
 
@@ -6241,6 +6244,11 @@ msgstr "[    okänt    ]"
 msgid "[  undef ]"
 msgstr "[ odefinierad ]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "aldrig"
+
 msgid "[marginal]"
 msgstr "[  marginell  ]"
 
index c9417fb..c40022d 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -483,6 +483,11 @@ msgstr "soket için tuz alınırken hata\n"
 msgid "error binding socket to '%s': %s\n"
 msgstr "soket `%s'e bağlanırken hata: %s\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "UYARI: %s üzerinde izinler güvensiz: \"%s\"\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "soket dinleme başarısız: %s\n"
@@ -503,11 +508,6 @@ msgid "directory '%s' created\n"
 msgstr "dizin `%s' oluşturuldu\n"
 
 #, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "UYARI: %s üzerinde izinler güvensiz: \"%s\"\n"
-
-#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "%s için stat() başarısız oldu: %s\n"
@@ -1964,13 +1964,13 @@ msgstr "anahtar parolası değiştirir"
 msgid "export keys"
 msgstr "anahtarları gönderir"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "anahtarları bir anahtar sunucusuna gönderir"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "anahtarları bir anahtar sunucusundan indirir"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "bir anahtar sunucusunda anahtarları arar"
 
 msgid "update all keys from a keyserver"
@@ -2580,6 +2580,9 @@ msgstr "zaman damgası çelişkilerini uyarı olarak bildirir"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|durum bilgisini bu FD'ye yazar"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Kullanımı: gpgv [seçenekler] [dosyalar] (yardım için -h)"
 
@@ -4083,6 +4086,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "%d indisli bir yardımcı anahtar yok\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "%u bite yuvarlandı\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "%s anahtarları %u bit ile %u bit arasında olmalı.\n"
@@ -4099,11 +4107,6 @@ msgstr "İstediğiniz anahtar uzunluğu nedir? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "İstenen anahtar uzunluğu: %u bit\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "%u bite yuvarlandı\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5808,15 +5811,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "%s komutu gönderilirken hata: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "genel anahtar %s yok: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error storing flags: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "bayraklar saklanırken hata: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5897,14 +5891,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5912,6 +5906,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error storing flags: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "bayraklar saklanırken hata: %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "boru oluşturulurken hata: %s\n"
@@ -6072,6 +6071,10 @@ msgstr "`%s' güvence modelli güvence veritabanı sınaması için gereksiz\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "`%s' güvence modelli güvence veritabanı güncellemesi için gereksiz\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "genel anahtar %s yok: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "lütfen bir --check-trustdb yapın\n"
 
@@ -6151,6 +6154,11 @@ msgstr "[    bilinmeyen   ]"
 msgid "[  undef ]"
 msgstr "[     tanımsız    ]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "asla    "
+
 msgid "[marginal]"
 msgstr "[   şöyle böyle   ]"
 
index b2d6860..0a1fdef 100644 (file)
--- a/po/uk.po
+++ b/po/uk.po
@@ -2,12 +2,12 @@
 # Copyright (C) 2011 Free Software Foundation, Inc.
 # This file is distributed under the same license as the GnuPG package.
 #
-# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2014, 2015.
+# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2014, 2015, 2016.
 msgid ""
 msgstr ""
 "Project-Id-Version: GNU gnupg 2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2015-10-23 19:33+0300\n"
+"PO-Revision-Date: 2016-05-10 18:21+0300\n"
 "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
 "Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
 "Language: uk\n"
@@ -366,10 +366,8 @@ msgstr "заборонити клієнтам позначати ключі як
 msgid "allow presetting passphrase"
 msgstr "дозволити попереднє встановлення пароля"
 
-#, fuzzy
-#| msgid "allow caller to override the pinentry"
 msgid "disallow caller to override the pinentry"
-msgstr "дозволити функції виклику перевизначати pinentry"
+msgstr "забоÑ\80онити функції виклику перевизначати pinentry"
 
 msgid "allow passphrase to be prompted through Emacs"
 msgstr "дозволити запит пароля з Emacs"
@@ -439,6 +437,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "помилка під час спроби прив’язування сокета до «%s»: %s\n"
 
 #, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "не вдалося встановити права доступу до «%s»: %s\n"
+
+#, c-format
 msgid "listen() failed: %s\n"
 msgstr "помилка listen(): %s\n"
 
@@ -454,11 +456,6 @@ msgstr "не вдалося створити каталог «%s»: %s\n"
 msgid "directory '%s' created\n"
 msgstr "створено каталог «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "Увага: визначення прав доступу не є безпечним для %s — «%s»\n"
-
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "помилка stat() щодо «%s»: %s\n"
@@ -721,10 +718,9 @@ msgstr "помилка під час спроби створення поток
 msgid "error forking process: %s\n"
 msgstr "помилка під час спроби розгалужування процесу: %s\n"
 
-#, fuzzy, c-format
-#| msgid "waiting for process %d to terminate failed: %s\n"
+#, c-format
 msgid "waiting for processes to terminate failed: %s\n"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð´Ð¾Ñ\87екаÑ\82иÑ\81Ñ\8f Ð·Ð°Ð²ÐµÑ\80Ñ\88еннÑ\8f Ð¿Ñ\80оÑ\86еÑ\81Ñ\83 %d: %s\n"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð´Ð¾Ñ\87екаÑ\82иÑ\81Ñ\8f Ð¿ÐµÑ\80еÑ\80иваннÑ\8f Ð¿Ñ\80оÑ\86еÑ\81Ñ\83: %s\n"
 
 #, c-format
 msgid "error running '%s': probably not installed\n"
@@ -763,10 +759,9 @@ msgstr "скасовано користувачем\n"
 msgid "problem with the agent\n"
 msgstr "проблема з агентом\n"
 
-#, fuzzy, c-format
-#| msgid "problem with the agent: %s\n"
+#, c-format
 msgid "problem with the agent (unexpected response \"%s\")\n"
-msgstr "проблема з агентом: %s\n"
+msgstr "проблема із агентом (неочікувана відповідь «%s»)\n"
 
 #, c-format
 msgid "can't disable core dumps: %s\n"
@@ -1166,10 +1161,9 @@ msgstr ""
 "символи quoted printable у кодуванні ASCII — ймовірно, використано "
 "помилковий MTA\n"
 
-#, fuzzy, c-format
-#| msgid "not human readable"
+#, c-format
 msgid "[ not human readable (%zu bytes: %s%s) ]"
-msgstr "незручне для читання"
+msgstr "[ незручне для читання (%zu байтів: %s%s) ]"
 
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
@@ -1187,19 +1181,11 @@ msgstr "назва примітки не повинна містити біль
 msgid "a notation value must not use any control characters\n"
 msgstr "у значенні примітки не повинно міститися керівних символів\n"
 
-#, fuzzy
-#| msgid "a notation name must not contain more than one '@' character\n"
 msgid "a notation name may not contain an '=' character\n"
-msgstr "назва примітки не повинна містити більше за один символ «@»\n"
+msgstr "назва позначення не може містити символів «=»\n"
 
-#, fuzzy
-#| msgid ""
-#| "a notation name must have only printable characters or spaces, and end "
-#| "with an '='\n"
 msgid "a notation name must have only printable characters or spaces\n"
-msgstr ""
-"назва примітки має складатися з друкованих символів або пробілів і "
-"завершуватися символом «=»\n"
+msgstr "назва примітки має складатися з друкованих символів або пробілів\n"
 
 msgid "WARNING: invalid notation data found\n"
 msgstr "УВАГА: виявлено некоректні дані примітки\n"
@@ -1211,19 +1197,17 @@ msgstr "не вдалося пропустити через проксі зап
 msgid "Enter passphrase: "
 msgstr "Введіть пароль: "
 
-#, fuzzy, c-format
-#| msgid "error creating keyring '%s': %s\n"
+#, c-format
 msgid "error getting version from '%s': %s\n"
-msgstr "помилка під час спроби створення сховища ключів «%s»: %s\n"
+msgstr "помилка під час спроби отримання даних щодо версії з «%s»: %s\n"
 
 #, c-format
 msgid "server '%s' is older than us (%s < %s)"
-msgstr ""
+msgstr "сервер «%s» має версію, старішу за нашу (%s < %s)"
 
-#, fuzzy, c-format
-#| msgid "WARNING: %s overrides %s\n"
+#, c-format
 msgid "WARNING: %s\n"
-msgstr "УВАГА: %s перевизначає %s\n"
+msgstr "УВАГА: %s\n"
 
 #, c-format
 msgid "OpenPGP card not available: %s\n"
@@ -1525,10 +1509,9 @@ msgstr "ключ «%s» не знайдено: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "помилка під час спроби читання блокування ключа: %s\n"
 
-#, fuzzy, c-format
-#| msgid "key \"%s\" not found: %s\n"
+#, c-format
 msgid "key \"%s\" not found\n"
-msgstr "ключ «%s» не знайдено: %s\n"
+msgstr "ключ «%s» не знайдено\n"
 
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(якщо ключ не задано відбитком)\n"
@@ -1721,24 +1704,22 @@ msgstr "помилка створення «%s»: %s.\n"
 msgid "[User ID not found]"
 msgstr "[Ідентифікатор не знайдено]"
 
-#, fuzzy, c-format
-#| msgid "missing argument for option \"%.50s\"\n"
+#, c-format
 msgid "(check argument of option '%s')\n"
-msgstr "не вказано аргументу до параметра «%.50s»\n"
+msgstr "(перевірте аргумент параметра «%s»)\n"
 
 #, c-format
 msgid "Warning: '%s' should be a long key ID or a fingerprint\n"
 msgstr ""
+"Попередження: «%s» має бути довгим ідентифікатором ключа або відбитком\n"
 
-#, fuzzy, c-format
-#| msgid "error closing %s: %s\n"
+#, c-format
 msgid "error looking up: %s\n"
-msgstr "помилка під час спроби закрити %s: %s\n"
+msgstr "помилка під час пошуку: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error creating keyring '%s': %s\n"
+#, c-format
 msgid "Warning: %s appears in the keyring %d times\n"
-msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ñ\81Ñ\82воÑ\80еннÑ\8f Ñ\81Ñ\85овиÑ\89а ÐºÐ»Ñ\8eÑ\87Ñ\96в Â«%s»: %s\n"
+msgstr "Ð\9fопеÑ\80едженнÑ\8f: Ð·Ð°Ð¿Ð¸Ñ\81 %s Ð½Ð°Ñ\8fвний Ñ\83 Ñ\81Ñ\85овиÑ\89Ñ\96 %d Ñ\80азÑ\96в\n"
 
 #, c-format
 msgid "automatically retrieved '%s' via %s\n"
@@ -1755,19 +1736,17 @@ msgstr "Без відбитка"
 msgid "secret key \"%s\" not found: %s\n"
 msgstr "закритий ключ «%s» не знайдено: %s\n"
 
-#, fuzzy, c-format
-#| msgid "|NAME|use NAME as default secret key"
+#, c-format
 msgid "Warning: not using '%s' as default key: %s\n"
-msgstr "|NAME|використовувати вказаний типовий закритий ключ"
+msgstr "Попередження: «%s» не використовується як типовий ключ: %s\n"
 
-#, fuzzy, c-format
-#| msgid "|NAME|use NAME as default secret key"
+#, c-format
 msgid "using \"%s\" as default secret key for signing\n"
-msgstr "|NAME|використовувати вказаний типовий закритий ключ"
+msgstr "використовуємо «%s» як типовий закритий ключ для підписування\n"
 
 #, c-format
 msgid "all values passed to '%s' ignored\n"
-msgstr ""
+msgstr "усі значення, передані «%s», проігноровано\n"
 
 #, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
@@ -1857,13 +1836,13 @@ msgstr "змінити пароль"
 msgid "export keys"
 msgstr "експортувати ключі"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "експортувати ключі на сервер ключів"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "імпортувати ключі з сервера ключів"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "шукати ключі на сервері ключів"
 
 msgid "update all keys from a keyserver"
@@ -1890,10 +1869,8 @@ msgstr "показати контрольні суми повідомлень"
 msgid "run in server mode"
 msgstr "запустити у режимі сервера"
 
-#, fuzzy
-#| msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
 msgid "|VALUE|set the TOFU policy for a key"
-msgstr "встановити правила TOFU для ключа (good, unknown, bad, ask, auto)"
+msgstr "|VALUE|встановити вказане правило TOFU для ключа"
 
 msgid "create ascii armored output"
 msgstr "створити дані у форматі ASCII"
@@ -2100,17 +2077,15 @@ msgstr "показувати назву сховища ключів у спис
 msgid "show expiration dates during signature listings"
 msgstr "показувати дати завершення строків дії у списку підписів"
 
-#, fuzzy
-#| msgid "Available keys:\n"
 msgid "available TOFU policies:\n"
-msgstr "Ð\94оÑ\81Ñ\82Ñ\83пнÑ\96 ÐºÐ»Ñ\8eÑ\87Ñ\96:\n"
+msgstr "можливÑ\96 Ð²Ð°Ñ\80Ñ\96анÑ\82и Ð¿Ñ\80авил TOFU:\n"
 
 #, c-format
 msgid "unknown TOFU policy '%s'\n"
 msgstr "невідомі правила TOFU «%s»\n"
 
 msgid "(use \"help\" to list choices)\n"
-msgstr ""
+msgstr "(команда «help» виводить список можливих варіантів)\n"
 
 #, c-format
 msgid "unknown TOFU DB format '%s'\n"
@@ -2403,10 +2378,9 @@ msgstr "помилка під час спроби отримання даних
 msgid "key export failed: %s\n"
 msgstr "помилка під час спроби експортування ключа: %s\n"
 
-#, fuzzy, c-format
-#| msgid "key export failed: %s\n"
+#, c-format
 msgid "export as ssh key failed: %s\n"
-msgstr "помилка під час спроби експортування ключа: %s\n"
+msgstr "спроба експортування ключа ssh зазнала невдачі: %s\n"
 
 #, c-format
 msgid "keyserver search failed: %s\n"
@@ -2428,16 +2402,13 @@ msgstr "помилка перетворення у формат ASCII: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "некоректний алгоритм хешування «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "error loading certificate '%s': %s\n"
+#, c-format
 msgid "error parsing key specification '%s': %s\n"
-msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ð·Ð°Ð²Ð°Ð½Ñ\82аженнÑ\8f Ñ\81еÑ\80Ñ\82иÑ\84Ñ\96каÑ\82а «%s»: %s\n"
+msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ð¾Ð±Ñ\80обки Ñ\81пеÑ\86иÑ\84Ñ\96каÑ\86Ñ\96Ñ\97 ÐºÐ»Ñ\8eÑ\87а «%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "'%s' does not appear to be a valid key id, fingerprint or key grip.\n"
+#, c-format
 msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
-msgstr "«%s» не є коректним ідентифікатором ключа, відбитком або keygrip.\n"
+msgstr "«%s» не є коректним ідентифікатором ключа, відбитком або кодом\n"
 
 msgid "[filename]"
 msgstr "[назва файла]"
@@ -2463,6 +2434,9 @@ msgstr "супроводжувати конфлікти часових позн
 msgid "|FD|write status info to this FD"
 msgstr "записувати до дескриптора файла дані щодо стану"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "Використання: gpgv [параметри] [файли] (-h — довідка)"
 
@@ -2748,6 +2722,8 @@ msgstr "ключ %s: закритий ключ з некоректним шиф
 #, c-format
 msgid "To migrate '%s', with each smartcard, run: %s\n"
 msgstr ""
+"Для перенесення «%s» на кожній із карток пам’яті слід виконати таку команду: "
+"%s\n"
 
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
@@ -2877,10 +2853,9 @@ msgstr "створено сховище ключів «%s»\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "ресурс блоку ключів «%s»: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error opening '%s': %s\n"
+#, c-format
 msgid "error opening key DB: %s\n"
-msgstr "помилка під час відкриття «%s»: %s\n"
+msgstr "помилка під час спроби відкрити базу даних ключів: %s\n"
 
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
@@ -2892,64 +2867,61 @@ msgstr "[відкликання]"
 msgid "[self-signature]"
 msgstr "[самопідпис]"
 
-#, fuzzy, c-format
-#| msgid "key %s: unsupported public key algorithm\n"
+#, c-format
 msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
-msgstr "ключ %s: непідтримуваний алгоритм створення відкритого ключа\n"
+msgstr ""
+"неможливо перевірити підпис із непідтримуваним алгоритмом створення "
+"відкритого ключа (%d): %s.\n"
 
-#, fuzzy, c-format
-#| msgid "card does not support digest algorithm %s\n"
+#, c-format
 msgid ""
 "can't check signature with unsupported message-digest algorithm %d: %s.\n"
-msgstr "карткою не підтримується алгоритм контрольних сум %s\n"
+msgstr ""
+"неможливо перевірити підпис із непідтримуваним алгоритмом створення "
+"контрольної суми %d: %s.\n"
 
-#, fuzzy
-#| msgid "Good signature from"
 msgid " (reordered signatures follow)"
-msgstr "Правильний підпис від"
+msgstr " (нижче наведено перевпорядковані підписи)"
 
-#, fuzzy, c-format
-#| msgid "key %s: %s\n"
+#, c-format
 msgid "key %s:\n"
-msgstr "ключ %s: %s\n"
+msgstr "ключ %s:\n"
 
-#, fuzzy, c-format
-#| msgid "User ID \"%s\": %d signature removed\n"
+#, c-format
 msgid "%d duplicate signature removed\n"
 msgid_plural "%d duplicate signatures removed\n"
-msgstr[0] "Ð\86денÑ\82иÑ\84Ñ\96каÑ\82оÑ\80 ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а Â«%s»: Ð²Ð¸Ð»Ñ\83Ñ\87ено %d Ð¿Ñ\96дпиÑ\81\n"
-msgstr[1] "Ð\86денÑ\82иÑ\84Ñ\96каÑ\82оÑ\80 ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а Â«%s»: Ð²Ð¸Ð»Ñ\83Ñ\87ено %d Ð¿Ñ\96дпиÑ\81\n"
-msgstr[2] "Ð\86денÑ\82иÑ\84Ñ\96каÑ\82оÑ\80 ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а Â«%s»: Ð²Ð¸Ð»Ñ\83Ñ\87ено %d Ð¿Ñ\96дпиÑ\81\n"
+msgstr[0] "вилÑ\83Ñ\87ено %d Ð´Ñ\83блÑ\96каÑ\82 Ð¿Ñ\96дпиÑ\81Ñ\83\n"
+msgstr[1] "вилÑ\83Ñ\87ено %d Ð´Ñ\83блÑ\96каÑ\82и Ð¿Ñ\96дпиÑ\81Ñ\96в\n"
+msgstr[2] "вилÑ\83Ñ\87ено %d Ð´Ñ\83блÑ\96каÑ\82Ñ\96в Ð¿Ñ\96дпиÑ\81Ñ\96в\n"
 
-#, fuzzy, c-format
-#| msgid "1 signature not checked due to a missing key\n"
+#, c-format
 msgid "%d signature not checked due to a missing key\n"
 msgid_plural "%d signatures not checked due to missing keys\n"
-msgstr[0] "1 підпис не перевірено через те, що немає ключа\n"
-msgstr[1] "1 підпис не перевірено через те, що немає ключа\n"
-msgstr[2] "1 підпис не перевірено через те, що немає ключа\n"
+msgstr[0] "%d підпис не перевірено через те, що немає ключа\n"
+msgstr[1] "%d підписи не перевірено через те, що немає ключа\n"
+msgstr[2] "%d підписів не перевірено через те, що немає ключа\n"
 
-#, fuzzy, c-format
-#| msgid "%d bad signatures\n"
+#, c-format
 msgid "%d bad signature\n"
 msgid_plural "%d bad signatures\n"
-msgstr[0] "%d помилкових підписів\n"
-msgstr[1] "%d помилкових підписів\n"
+msgstr[0] "%d помилкових підпис\n"
+msgstr[1] "%d помилкових підписи\n"
 msgstr[2] "%d помилкових підписів\n"
 
-#, fuzzy, c-format
-#| msgid "Good signature from"
+#, c-format
 msgid "%d signature reordered\n"
 msgid_plural "%d signatures reordered\n"
-msgstr[0] "Ð\9fÑ\80авилÑ\8cний Ð¿Ñ\96дпиÑ\81 Ð²Ñ\96д"
-msgstr[1] "Ð\9fÑ\80авилÑ\8cний Ð¿Ñ\96дпиÑ\81 Ð²Ñ\96д"
-msgstr[2] "Ð\9fÑ\80авилÑ\8cний Ð¿Ñ\96дпиÑ\81 Ð²Ñ\96д"
+msgstr[0] "пеÑ\80евпоÑ\80Ñ\8fдковано %d Ð¿Ñ\96дпиÑ\81\n"
+msgstr[1] "пеÑ\80евпоÑ\80Ñ\8fдковано %d Ð¿Ñ\96дпиÑ\81и\n"
+msgstr[2] "пеÑ\80евпоÑ\80Ñ\8fдковано %d Ð¿Ñ\96дпиÑ\81Ñ\96в\n"
 
 #, c-format
 msgid ""
 "Warning: errors found and only checked self-signatures, run '%s' to check "
 "all signatures.\n"
 msgstr ""
+"Попередження: виявлено помилки, перевірка виконувалася лише для "
+"самопідписування, віддайте команду «%s», щоб перевірити усі підписи.\n"
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -2985,7 +2957,7 @@ msgstr ""
 
 #, c-format
 msgid "Skipping user ID \"%s\", which is not a text ID.\n"
-msgstr ""
+msgstr "Пропускаємо ідентифікатор користувача «%s», який не є текстовим.\n"
 
 #, c-format
 msgid "User ID \"%s\" is revoked."
@@ -3294,10 +3266,8 @@ msgstr "Ключ відкликано."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Підписати всі ідентифікатори користувача? (y/N або т/Н) "
 
-#, fuzzy
-#| msgid "Really sign all user IDs? (y/N) "
 msgid "Really sign all text user IDs? (y/N) "
-msgstr "Підписати всі ідентифікатори користувача? (y/N або т/Н) "
+msgstr "Ð\9fÑ\96дпиÑ\81аÑ\82и Ð²Ñ\81Ñ\96 Ñ\82екÑ\81Ñ\82овÑ\96 Ñ\96денÑ\82иÑ\84Ñ\96каÑ\82оÑ\80и ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а? (y/N Ð°Ð±Ð¾ Ñ\82\9d) "
 
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Підказка: виберіть ідентифікатори користувача для підписування\n"
@@ -3405,10 +3375,9 @@ msgstr "«%s» не є відбитком\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "«%s» не є основним відбитком\n"
 
-#, fuzzy, c-format
-#| msgid "invalid value\n"
+#, c-format
 msgid "Invalid user ID '%s': %s\n"
-msgstr "некоÑ\80екÑ\82не Ð·Ð½Ð°Ñ\87еннÑ\8f\n"
+msgstr "Ð\9dекоÑ\80екÑ\82ний Ñ\96денÑ\82иÑ\84Ñ\96каÑ\82оÑ\80 ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а Â«%s»: %s\n"
 
 msgid "No matching user IDs."
 msgstr "Немає відповідних ідентифікаторів користувачів."
@@ -3538,13 +3507,12 @@ msgstr "Вилучити цей невідомий підпис? (y/N/q або 
 msgid "Really delete this self-signature? (y/N)"
 msgstr "Вилучити цей самопідпис? (y/N або т/Н)"
 
-#, fuzzy, c-format
-#| msgid "Deleted %d signature.\n"
+#, c-format
 msgid "Deleted %d signature.\n"
 msgid_plural "Deleted %d signatures.\n"
 msgstr[0] "Вилучено %d підпис.\n"
-msgstr[1] "Вилучено %d підпис.\n"
-msgstr[2] "Вилучено %d підпис.\n"
+msgstr[1] "Вилучено %d підписи.\n"
+msgstr[2] "Вилучено %d підписів.\n"
 
 msgid "Nothing deleted.\n"
 msgstr "Нічого не вилучено.\n"
@@ -3556,13 +3524,12 @@ msgstr "некоректний"
 msgid "User ID \"%s\" compacted: %s\n"
 msgstr "Ідентифікатор користувача «%s» ущільнено: %s\n"
 
-#, fuzzy, c-format
-#| msgid "User ID \"%s\": %d signature removed\n"
+#, c-format
 msgid "User ID \"%s\": %d signature removed\n"
 msgid_plural "User ID \"%s\": %d signatures removed\n"
 msgstr[0] "Ідентифікатор користувача «%s»: вилучено %d підпис\n"
-msgstr[1] "Ідентифікатор користувача «%s»: вилучено %d підпис\n"
-msgstr[2] "Ідентифікатор користувача «%s»: вилучено %d підпис\n"
+msgstr[1] "Ідентифікатор користувача «%s»: вилучено %d підписів\n"
+msgstr[2] "Ідентифікатор користувача «%s»: вилучено %d підписів\n"
 
 #, c-format
 msgid "User ID \"%s\": already minimized\n"
@@ -3606,15 +3573,12 @@ msgstr ""
 "Ви справді бажаєте призначити цей ключ як підписане відкликання? (y/N або т/"
 "Н) "
 
-#, fuzzy
-#| msgid ""
-#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgid ""
 "Are you sure you want to change the expiration time for multiple subkeys? (y/"
 "N) "
 msgstr ""
-"Ви справді бажаєте призначити цей ключ як підписане відкликання? (y/N або т/"
-"Н) "
+"Ви справді хочете змінити час вичерпання строку дії для декількох підключів? "
+"(y/N або т/Н) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Зміна часу завершення строку дії для підключа.\n"
@@ -3665,10 +3629,9 @@ msgstr "Ідентифікатора користувача з індексом
 msgid "No user ID with hash %s\n"
 msgstr "Ідентифікатора користувача з хешем %s не існує\n"
 
-#, fuzzy, c-format
-#| msgid "No subkey with index %d\n"
+#, c-format
 msgid "No subkey with key ID '%s'.\n"
-msgstr "Ð\9fÑ\96дклÑ\8eÑ\87а Ð· Ñ\96ндекÑ\81ом %d Ð½Ðµ Ñ\96Ñ\81нÑ\83Ñ\94\n"
+msgstr "Ð\9fÑ\96клÑ\8eÑ\87а Ñ\96з Ñ\96денÑ\82иÑ\84Ñ\96каÑ\82оÑ\80ом ÐºÐ»Ñ\8eÑ\87а Â«%s» Ð½Ðµ Ñ\96Ñ\81нÑ\83Ñ\94.\n"
 
 #, c-format
 msgid "No subkey with index %d\n"
@@ -3894,6 +3857,10 @@ msgid "No key with this keygrip\n"
 msgstr "Немає ключів з таким значенням keygrip\n"
 
 #, c-format
+msgid "rounded to %u bits\n"
+msgstr "округлено до %u бітів\n"
+
+#, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "ключі %s можуть мати довжину від %u до %u бітів.\n"
 
@@ -3909,10 +3876,6 @@ msgstr "Якою має бути довжина ключа? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "Запитана довжина ключа — %u бітів\n"
 
-#, c-format
-msgid "rounded to %u bits\n"
-msgstr "округлено до %u бітів\n"
-
 msgid "Please select which elliptic curve you want:\n"
 msgstr "Вкажіть потрібну вам еліптичну криву:\n"
 
@@ -4018,7 +3981,7 @@ msgstr "Некоректний символ у імені\n"
 
 #, c-format
 msgid "The characters '%s' and '%s' may not appear in name\n"
-msgstr ""
+msgstr "Не можна використовувати символи «%s» і «%s» у назві\n"
 
 msgid "Name may not start with a digit\n"
 msgstr "Ім’я не може починатися з цифри\n"
@@ -4208,30 +4171,26 @@ msgstr "Критична примітка підпису: "
 msgid "Signature notation: "
 msgstr "Примітка підпису: "
 
-#, fuzzy, c-format
-#| msgid "%d good signatures\n"
+#, c-format
 msgid "%d good signature\n"
 msgid_plural "%d good signatures\n"
-msgstr[0] "%d добрих підписів\n"
-msgstr[1] "%d добрих підписів\n"
+msgstr[0] "%d добрий підпис\n"
+msgstr[1] "%d добрих підписи\n"
 msgstr[2] "%d добрих підписів\n"
 
-#, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
+#, c-format
 msgid "%d signature not checked due to an error\n"
 msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 підпис не перевірено через помилку\n"
-msgstr[1] "1 підпис не перевірено через помилку\n"
-msgstr[2] "1 підпис не перевірено через помилку\n"
+msgstr[0] "%d підпис не перевірено через помилку\n"
+msgstr[1] "%d підписи не перевірено через помилку\n"
+msgstr[2] "%d підписів не перевірено через помилку\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: %lu key(s) skipped due to their large size\n"
+#, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
-msgstr[0] ""
-"Попередження: %lu ключів пропущено через їхній надто великий розмір\n"
+msgstr[0] "Попередження: %lu ключ пропущено через надто великий розмір\n"
 msgstr[1] ""
-"Попередження: %lu ключів пропущено через їхній надто великий розмір\n"
+"Попередження: %lu ключі пропущено через їхній надто великий розмір\n"
 msgstr[2] ""
 "Попередження: %lu ключів пропущено через їхній надто великий розмір\n"
 
@@ -4266,29 +4225,26 @@ msgstr "Серійний номер картки ="
 msgid "caching keyring '%s'\n"
 msgstr "кешування сховища ключів «%s»\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys cached so far (%lu signatures)\n"
+#, c-format
 msgid "%lu keys cached so far (%lu signature)\n"
 msgid_plural "%lu keys cached so far (%lu signatures)\n"
-msgstr[0] "зараз кешовано %lu ключів (%lu підписів)\n"
-msgstr[1] "зараз кешовано %lu ключів (%lu підписів)\n"
+msgstr[0] "зараз кешовано %lu ключів (%lu підпис)\n"
+msgstr[1] "зараз кешовано %lu ключів (%lu підписи)\n"
 msgstr[2] "зараз кешовано %lu ключів (%lu підписів)\n"
 
-#, fuzzy, c-format
-#| msgid "flush the cache"
+#, c-format
 msgid "%lu key cached"
 msgid_plural "%lu keys cached"
-msgstr[0] "спорожнити кеш"
-msgstr[1] "спорожнити кеш"
-msgstr[2] "спорожнити кеш"
+msgstr[0] "кешовано %lu ключ"
+msgstr[1] "кешовано %lu ключі"
+msgstr[2] "кешовано %lu ключів"
 
-#, fuzzy, c-format
-#| msgid "1 bad signature\n"
+#, c-format
 msgid " (%lu signature)\n"
 msgid_plural " (%lu signatures)\n"
-msgstr[0] "1 помилковий підпис\n"
-msgstr[1] "1 помилковий підпис\n"
-msgstr[2] "1 помилковий підпис\n"
+msgstr[0] " (%lu підпис)\n"
+msgstr[1] " (%lu підписи)\n"
+msgstr[2] " (%lu підписів)\n"
 
 #, c-format
 msgid "%s: keyring created\n"
@@ -4330,12 +4286,11 @@ msgstr "некоректний протокол сервера ключів (н
 msgid "\"%s\" not a key ID: skipping\n"
 msgstr "«%s» не є ідентифікатором ключа: пропускаємо\n"
 
-#, fuzzy, c-format
-#| msgid "refreshing %d keys from %s\n"
+#, c-format
 msgid "refreshing %d key from %s\n"
 msgid_plural "refreshing %d keys from %s\n"
-msgstr[0] "оновлюємо %d ключів з %s\n"
-msgstr[1] "оновлюємо %d ключів з %s\n"
+msgstr[0] "оновлюємо %d ключ з %s\n"
+msgstr[1] "оновлюємо %d ключі з %s\n"
 msgstr[2] "оновлюємо %d ключів з %s\n"
 
 #, c-format
@@ -4361,10 +4316,8 @@ msgstr "надсилаємо запит щодо ключа %s до %s серв
 msgid "requesting key %s from %s\n"
 msgstr "надсилаємо запит щодо ключа %s з %s\n"
 
-#, fuzzy
-#| msgid "invalid keyserver options\n"
 msgid "no keyserver known\n"
-msgstr "некоÑ\80екÑ\82нÑ\96 Ð¿Ð°Ñ\80амеÑ\82Ñ\80и Ñ\81еÑ\80веÑ\80а ключів\n"
+msgstr "немаÑ\94 Ð²Ñ\96домиÑ\85 Ñ\81еÑ\80веÑ\80Ñ\96в ключів\n"
 
 #, c-format
 msgid "sending key %s to %s\n"
@@ -4584,18 +4537,16 @@ msgstr "УВАГА: алгоритм обчислення контрольних
 msgid "Note: signatures using the %s algorithm are rejected\n"
 msgstr "Зауваження: підписи за допомогою алгоритму %s відкинуто\n"
 
-#, fuzzy, c-format
-#| msgid "%s:%u: read error: %s\n"
+#, c-format
 msgid "(reported error: %s)\n"
-msgstr "%s:%u: помилка під час читання: %s\n"
+msgstr "(повідомлена помилка: %s)\n"
 
-#, fuzzy, c-format
-#| msgid "read error in '%s': %s\n"
+#, c-format
 msgid "(reported error: %s <%s>)\n"
-msgstr "помилка читання у «%s»: %s\n"
+msgstr "(повідомлена помилка: %s <%s>)\n"
 
 msgid "(further info: "
-msgstr ""
+msgstr "(подальша інформація: "
 
 #, c-format
 msgid "%s:%d: deprecated option \"%s\"\n"
@@ -4646,10 +4597,9 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 "Відкритий ключ ECDSA має зберігатися у кодуванні SEC кратному 8-бітовому\n"
 
-#, fuzzy, c-format
-#| msgid "Unknown signature type '%s'\n"
+#, c-format
 msgid "unknown weak digest '%s'\n"
-msgstr "Ð\9dевÑ\96домий Ñ\82ип Ð¿Ñ\96дпиÑ\81Ñ\83 «%s»\n"
+msgstr "невÑ\96дома Ñ\81лабка ÐºÐ¾Ð½Ñ\82Ñ\80олÑ\8cна Ñ\81Ñ\83ма «%s»\n"
 
 #, c-format
 msgid "File '%s' exists. "
@@ -4993,20 +4943,17 @@ msgstr "%s: пропущено: відкритий ключ вимкнено\n"
 msgid "%s: skipped: public key already present\n"
 msgstr "%s: пропущено: відкритий ключ вже існує\n"
 
-#, fuzzy, c-format
-#| msgid "can't connect to '%s': %s\n"
+#, c-format
 msgid "can't encrypt to '%s'\n"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ñ\81Ñ\82ановиÑ\82и Ð·â\80\99Ñ\94днаннÑ\8f Ð· Â«%s»: %s\n"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ñ\88иÑ\84Ñ\80Ñ\83ваÑ\82и Ð´Ð¾ Â«%s»\n"
 
-#, fuzzy, c-format
-#| msgid "line %d: invalid date given\n"
+#, c-format
 msgid "option '%s' given, but no valid default keys given\n"
-msgstr "рядок %d: вказано некоректну дату\n"
+msgstr "вказано параметр «%s», але не вказано коректних типових ключів\n"
 
-#, fuzzy, c-format
-#| msgid "line %d: invalid date given\n"
+#, c-format
 msgid "option '%s' given, but option '%s' not given\n"
-msgstr "рядок %d: вказано некоректну дату\n"
+msgstr "вказано параметр «%s», але не вказано параметр «%s»\n"
 
 msgid "You did not specify a user ID. (you may use \"-r\")\n"
 msgstr ""
@@ -5142,13 +5089,11 @@ msgid ""
 "declare that a key shall not anymore be used.  It is not possible\n"
 "to retract such a revocation certificate once it has been published."
 msgstr ""
+"Сертифікат відкликання є своєрідним «апаратним вимикачем» для\n"
+"відкритого оголошення, що ключ не можна більше використовувати.\n"
+"Такий сертифікат відкликання не можна скасовувати після його\n"
+"оприлюднення."
 
-#, fuzzy
-#| msgid ""
-#| "Use it to revoke this key in case of a compromise or loss of\n"
-#| "the secret key.  However, if the secret key is still accessible,\n"
-#| "it is better to generate a new revocation certificate and give\n"
-#| "a reason for the revocation."
 msgid ""
 "Use it to revoke this key in case of a compromise or loss of\n"
 "the secret key.  However, if the secret key is still accessible,\n"
@@ -5159,13 +5104,10 @@ msgstr ""
 "Скористайтеся цим для відкликання цього ключа у випадку його\n"
 "компрометації або втрати закритої частини. Втім, якщо доступ до\n"
 "закритого ключа не втрачено, краще створити новий сертифікат\n"
-"відкликання і вказати причину відкликання."
+"відкликання і вказати причину відкликання. Докладніший опис\n"
+"можна знайти у розділах підручника з GnuPG щодо команди\n"
+"gpg «--gen-revoke»."
 
-#, fuzzy
-#| msgid ""
-#| "To avoid an accidental use of this file, a colon has been inserted\n"
-#| "before the 5 dashes below.  Remove this colon with a text editor\n"
-#| "before making use of this revocation certificate."
 msgid ""
 "To avoid an accidental use of this file, a colon has been inserted\n"
 "before the 5 dashes below.  Remove this colon with a text editor\n"
@@ -5173,29 +5115,27 @@ msgid ""
 msgstr ""
 "Щоб уникнути випадкового використання цього файла, перед п’ятьма\n"
 "дефісами нижче додано двокрапку. Вилучіть цю двокрапку у текстовому\n"
-"редакторі, перш ніж скористатися цим сертифікатом відкликання."
+"редакторі, перш ніж імпортувати або оприлюднювати цей сертифікат\n"
+"відкликання."
 
-#, fuzzy, c-format
-#| msgid "Revocation certificate created.\n"
+#, c-format
 msgid "revocation certificate stored as '%s.rev'\n"
-msgstr "Створено сертифікат відкликання.\n"
+msgstr "сертифікат відкликання збережено як «%s.rev»\n"
 
-#, fuzzy, c-format
-#| msgid "secret key \"%s\" not found: %s\n"
+#, c-format
 msgid "secret key \"%s\" not found\n"
-msgstr "закритий ключ «%s» не знайдено: %s\n"
+msgstr "закритий ключ «%s» не знайдено\n"
 
 #. TRANSLATORS: The %s prints a key specification which
 #. for example has been given at the command line.  Several lines
 #. lines with secret key infos are printed after this message.
 #, c-format
 msgid "'%s' matches multiple secret keys:\n"
-msgstr ""
+msgstr "«%s» відповідає декільком закритим ключам:\n"
 
-#, fuzzy, c-format
-#| msgid "error creating keyring '%s': %s\n"
+#, c-format
 msgid "error searching the keyring: %s\n"
-msgstr "помилка під час спроби створення сховища ключів «%s»: %s\n"
+msgstr "помилка під час спроби пошуку у сховищі ключів: %s\n"
 
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Створити сертифікат відкликання для цього ключа? (y/N або т/Н) "
@@ -5277,25 +5217,21 @@ msgid "WARNING: signing subkey %s has an invalid cross-certification\n"
 msgstr ""
 "УВАГА: підписування підключа %s містить некоректну перехресну сертифікацію\n"
 
-#, fuzzy, c-format
-#| msgid "public key %s is %lu second newer than the signature\n"
+#, c-format
 msgid "public key %s is %lu second newer than the signature\n"
 msgid_plural "public key %s is %lu seconds newer than the signature\n"
 msgstr[0] "відкритий ключ %s є на %lu секунду новішим за підпис\n"
-msgstr[1] "відкритий ключ %s є на %lu секунду новішим за підпис\n"
-msgstr[2] "відкритий ключ %s є на %lu секунду новішим за підпис\n"
+msgstr[1] "відкритий ключ %s є на %lu секунди новішим за підпис\n"
+msgstr[2] "відкритий ключ %s є на %lu секунд новішим за підпис\n"
 
-#, fuzzy, c-format
-#| msgid "public key %s is %lu second newer than the signature\n"
+#, c-format
 msgid "public key %s is %lu day newer than the signature\n"
 msgid_plural "public key %s is %lu days newer than the signature\n"
-msgstr[0] "відкритий ключ %s є на %lu секунду новішим за підпис\n"
-msgstr[1] "відкритий ключ %s є на %lu секунду новішим за підпис\n"
-msgstr[2] "відкритий ключ %s є на %lu секунду новішим за підпис\n"
+msgstr[0] "відкритий ключ %s є на %lu день новішим за підпис\n"
+msgstr[1] "відкритий ключ %s є на %lu дні новішим за підпис\n"
+msgstr[2] "відкритий ключ %s є на %lu днів новішим за підпис\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid ""
 "key %s was created %lu second in the future (time warp or clock problem)\n"
 msgid_plural ""
@@ -5310,20 +5246,18 @@ msgstr[2] ""
 "ключ %s було створено з позначкою на %lu секунду у майбутньому (часова петля "
 "або проблема з годинником)\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid "key %s was created %lu day in the future (time warp or clock problem)\n"
 msgid_plural ""
 "key %s was created %lu days in the future (time warp or clock problem)\n"
 msgstr[0] ""
-"ключ %s було створено з позначкою на %lu секунду у майбутньому (часова петля "
+"ключ %s було створено з позначкою на %lu день у майбутньому (часова петля "
 "або проблема з годинником)\n"
 msgstr[1] ""
-"ключ %s було створено з позначкою на %lu секунду у майбутньому (часова петля "
-"або Ð¿Ñ\80облема Ð· Ð³Ð¾Ð´Ð¸Ð½Ð½Ð¸ÐºÐ¾Ð¼)\n"
+"ключ %s було створено з позначкою на %lu дні у майбутньому (часова петля або "
+"проблема з годинником)\n"
 msgstr[2] ""
-"ключ %s було створено з позначкою на %lu секунду у майбутньому (часова петля "
+"ключ %s було створено з позначкою на %lu днів у майбутньому (часова петля "
 "або проблема з годинником)\n"
 
 #, c-format
@@ -5553,228 +5487,226 @@ msgstr ""
 msgid "input line longer than %d characters\n"
 msgstr "рядок вхідних даних довший за %d символів\n"
 
-#, fuzzy, c-format
-#| msgid "error sending standard options: %s\n"
+#, c-format
 msgid "error beginning transaction on TOFU database: %s\n"
-msgstr "помилка під час спроби надсилання стандартних параметрів: %s\n"
+msgstr ""
+"помилка під час спроби розпочати внесення змін до бази даних TOFU: %s\n"
 
 #, c-format
 msgid "error committing transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "помилка під час внесення змін до бази даних TOFU: %s\n"
 
 #, c-format
 msgid "error rolling back transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "помилка під час скасовування змін у базі даних TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "unsupported algorithm: %s"
+#, c-format
 msgid "unsupported TOFU database version: %s\n"
-msgstr "непÑ\96дÑ\82Ñ\80имÑ\83ваний Ð°Ð»Ð³Ð¾Ñ\80иÑ\82м: %s"
+msgstr "непÑ\96дÑ\82Ñ\80имÑ\83вана Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\8f Ð±Ð°Ð·Ð¸ Ð´Ð°Ð½Ð¸Ñ\85 TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
+#, c-format
 msgid "error reading TOFU database: %s\n"
-msgstr "помилка під час спроби надсилання даних: %s\n"
+msgstr "помилка під час спроби читання бази даних TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error writing base64 encoding: %s\n"
+#, c-format
 msgid "error determining TOFU database's version: %s\n"
-msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ð·Ð°Ð¿Ð¸Ñ\81Ñ\83 Ñ\83 ÐºÐ¾Ð´Ñ\83ваннÑ\96 base64: %s\n"
+msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ð²Ð¸Ð·Ð½Ð°Ñ\87еннÑ\8f Ð²ÐµÑ\80Ñ\81Ñ\96Ñ\97 Ð±Ð°Ð·Ð¸ Ð´Ð°Ð½Ð¸Ñ\85 TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error initializing reader object: %s\n"
+#, c-format
 msgid "error initializing TOFU database: %s\n"
-msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96заÑ\86Ñ\96Ñ\97 Ð¾Ð±â\80\99Ñ\94кÑ\82а Ñ\87иÑ\82аннÑ\8f: %s\n"
+msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96заÑ\86Ñ\96Ñ\97 Ð±Ð°Ð·Ð¸ Ð´Ð°Ð½Ð¸Ñ\85 TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error opening '%s': %s\n"
+#, c-format
 msgid "error opening TOFU database '%s': %s\n"
-msgstr "помилка під час відкриття «%s»: %s\n"
+msgstr "помилка під час спроби відкрити бази даних TOFU «%s»: %s\n"
 
 msgid "Warning: Home directory contains both tofu.db and tofu.d.\n"
 msgstr ""
+"Попередження: у домашньому каталозі містяться як tofu.db, так і tofu.d.\n"
 
 msgid "Using split format for TOFU database\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
-msgid "error updating TOFU database: %s\n"
-msgstr "помилка під час спроби надсилання даних: %s\n"
+msgstr "Використовуємо розділений формат для бази даних TOFU\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "відкритий ключ %s не знайдено: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error setting OCSP target: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "помилка під час встановлення призначення за OCSP: %s\n"
+msgid "error updating TOFU database: %s\n"
+msgstr "помилка під час спроби оновлення бази даних TOFU: %s\n"
 
 #, c-format
 msgid "The binding %s is NOT known."
-msgstr ""
+msgstr "Прив’язка %s є невідомою."
 
 #, c-format
 msgid ""
 "The key with fingerprint %s raised a conflict with the binding %s.  Since "
 "this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
+"Ключ із відбитком %s конфліктує із прив’язкою %s. Оскільки правилами цієї "
+"прив’язки визначалося «автоматично», їх змінено на «запитувати»."
 
 #, c-format
 msgid ""
 "Please indicate whether you believe the binding %s%sis legitimate (the key "
 "belongs to the stated owner) or a forgery (bad)."
 msgstr ""
+"Будь ласка, вкажіть, чи вважаєте прив’язку %s%sчинною (ключ належить "
+"декларованому власнику) чи підробною (помилковою)."
 
-#, fuzzy, c-format
-#| msgid "error getting responder ID: %s\n"
+#, c-format
 msgid "error gathering other user IDs: %s\n"
-msgstr "помилка під час спроби отримання ідентифікатора відповідача: %s\n"
+msgstr "помилка під час збирання інших ідентифікаторів користувачів: %s\n"
 
 msgid "Known user IDs associated with this key:\n"
-msgstr ""
+msgstr "Відомі ідентифікатори користувачів, пов’язані із цим ключем:\n"
 
-#, fuzzy, c-format
-#| msgid "validity: %s"
+#, c-format
 msgid "policy: %s"
-msgstr "чинність: %s"
+msgstr "правило: %s"
 
-#, fuzzy, c-format
-#| msgid "error getting stored flags: %s\n"
+#, c-format
 msgid "error gathering signature stats: %s\n"
-msgstr "помилка під час спроби отримання збережених прапорців: %s\n"
+msgstr ""
+"помилка під час спроби зібрати статистичні дані щодо підписування: %s\n"
 
 #, c-format
 msgid "The email address \"%s\" is associated with %d key:\n"
 msgid_plural "The email address \"%s\" is associated with %d keys:\n"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Адресу електронної пошти «%s» пов’язано із %d ключем:\n"
+msgstr[1] "Адресу електронної пошти «%s» пов’язано із %d ключами:\n"
+msgstr[2] "Адресу електронної пошти «%s» пов’язано із %d ключами:\n"
 
 #, c-format
 msgid "Statistics for keys with the email address \"%s\":\n"
-msgstr ""
+msgstr "Статистичні дані для ключів із адресою електронної пошти «%s»:\n"
 
-#, fuzzy
-#| msgid "list keys"
 msgid "this key"
-msgstr "показати список ключів"
+msgstr "цей ключ"
 
 #, c-format
 msgid "%ld message signed in the future."
 msgid_plural "%ld messages signed in the future."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%ld повідомлення підписано у майбутньому."
+msgstr[1] "%ld повідомлення підписано у майбутньому."
+msgstr[2] "%ld повідомлень підписано у майбутньому."
 
-#, fuzzy, c-format
-#| msgid "print message digests"
+#, c-format
 msgid "%ld message signed"
 msgid_plural "%ld messages signed"
-msgstr[0] "показати контрольні суми повідомлень"
-msgstr[1] "показати контрольні суми повідомлень"
-msgstr[2] "показати контрольні суми повідомлень"
+msgstr[0] "підписано %ld повідомлення"
+msgstr[1] "підписано %ld повідомлення"
+msgstr[2] "підписано %ld повідомлень"
 
 #, c-format
 msgid " over the past %ld day."
 msgid_plural " over the past %ld days."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] " протягом %ld попереднього дня."
+msgstr[1] " протягом %ld попередніх днів."
+msgstr[2] " протягом %ld попередніх днів."
 
 #, c-format
 msgid " over the past %ld week."
 msgid_plural " over the past %ld weeks."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] " протягом %ld попереднього тижня."
+msgstr[1] " протягом %ld попередніх тижнів."
+msgstr[2] " протягом %ld попередніх тижнів."
 
 #, c-format
 msgid " over the past %ld month."
 msgid_plural " over the past %ld months."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] " протягом %ld попереднього місяця."
+msgstr[1] " протягом %ld попередніх місяців."
+msgstr[2] " протягом %ld попередніх місяців."
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
+"Зазвичай, з певною адресою електронної пошти пов’язано лише один ключ. Втім, "
+"іноді створюють новий ключ, коли, наприклад, ключ є надто застарілим або "
+"власник вважає, що ключ може бути скомпрометовано. Якщо ж таких обставин не "
+"передбачається, створення зайвого ключа може означати, що хтось намагається "
+"втрутитися і перехопити дані. Перш ніж приймати такий ключ, варто зв’язатися "
+"із власником і переконатися, що новий ключ є чинним."
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
-msgstr ""
+msgstr "gGaAuUrRbB"
 
 msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
+"(G)Добрий, (A)Прийняти одноразово, (U)Невідомий, (R)Відкинути одноразово, "
+"(B)Поганий? "
 
-#, fuzzy, c-format
-#| msgid "error creating a pipe: %s\n"
+#, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr ""
+"помилка під час спроби встановлення рівня довіри до прив’язки TOFU до %s\n"
+
+#, c-format
 msgid "error changing TOFU policy: %s\n"
-msgstr "помилка під час спроби створення каналу: %s\n"
+msgstr "помилка під час спроби змінити правила TOFU: %s\n"
 
 #. TRANSLATORS: The tilde ('~') is used here to indicate a
 #. * non-breakable space
 #, c-format
 msgid "%d~year"
 msgid_plural "%d~years"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d~рік"
+msgstr[1] "%d~роки"
+msgstr[2] "%d~років"
 
 #, c-format
 msgid "%d~month"
 msgid_plural "%d~months"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d~місяць"
+msgstr[1] "%d~місяці"
+msgstr[2] "%d~місяців"
 
 #, c-format
 msgid "%d~day"
 msgid_plural "%d~days"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d~день"
+msgstr[1] "%d~дні"
+msgstr[2] "%d~днів"
 
 #, c-format
 msgid "%d~hour"
 msgid_plural "%d~hours"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d~година"
+msgstr[1] "%d~години"
+msgstr[2] "%d~годин"
 
 #, c-format
 msgid "%d~minute"
 msgid_plural "%d~minutes"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d~хвилина"
+msgstr[1] "%d~хвилини"
+msgstr[2] "%d~хвилин"
 
 #, c-format
 msgid "%d~second"
 msgid_plural "%d~seconds"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d~секунда"
+msgstr[1] "%d~секунди"
+msgstr[2] "%d~секунд"
 
 #, c-format
 msgid "Have never verified a message signed by key %s!\n"
-msgstr ""
+msgstr "Ніколи не перевірялося повідомлення, підписане ключем %s!\n"
 
 #, c-format
 msgid ""
 "Failed to collect signature statistics for \"%s\"\n"
 "(key %s)\n"
 msgstr ""
+"Не вдалося зібрати статистичні дані щодо підписування для «%s»\n"
+"(ключ %s)\n"
 
-#, fuzzy, c-format
-#| msgid "print message digests"
+#, c-format
 msgid "Verified %ld messages signed by \"%s\"."
-msgstr "показаÑ\82и ÐºÐ¾Ð½Ñ\82Ñ\80олÑ\8cнÑ\96 Ñ\81Ñ\83ми Ð¿Ð¾Ð²Ñ\96домленÑ\8c"
+msgstr "Ð\9fеÑ\80евÑ\96Ñ\80ено %ld Ð¿Ð¾Ð²Ñ\96домленÑ\8c, Ð¿Ñ\96дпиÑ\81аниÑ\85 Â«%s»."
 
 #, c-format
 msgid ""
@@ -5784,18 +5716,24 @@ msgid_plural ""
 "Verified %ld messages signed by \"%s\"\n"
 "in the past %s."
 msgstr[0] ""
+"Перевірено %ld повідомлення, підписане «%s»,\n"
+"протягом такого строку: %s."
 msgstr[1] ""
+"Перевірено %ld повідомлення, підписаних «%s»,\n"
+"протягом такого строку: %s."
 msgstr[2] ""
+"Перевірено %ld повідомлень, підписаних «%s»,\n"
+"протягом такого строку: %s."
 
 #, c-format
 msgid "The most recent message was verified %s ago."
-msgstr ""
+msgstr "Останнє повідомлення було перевірено %s тому."
 
 msgid "Warning: we've have yet to see a message signed by this key!\n"
-msgstr ""
+msgstr "Попередження: повідомлень, які було б підписано цим ключем, не було!\n"
 
 msgid "Warning: we've only seen a single message signed by this key!\n"
-msgstr ""
+msgstr "Попередження: цим ключем було підписано лише одне повідомлення!\n"
 
 #, c-format
 msgid ""
@@ -5811,13 +5749,30 @@ msgid_plural ""
 "  %s\n"
 "to mark it as being bad.\n"
 msgstr[0] ""
+"Попередження: якщо вам здається, що у вас було понад %ld повідомлення, "
+"підписане цим ключем, цей ключ може бути підробним! Уважно перевірте, чи "
+"точно вказано адресу електронної пошти. Якщо ключ є підозріливим, "
+"скористайтеся командою\n"
+"  %s\n"
+"для позначення ключа як помилкового.\n"
 msgstr[1] ""
+"Попередження: якщо вам здається, що у вас було понад %ld повідомлення, "
+"підписане цим ключем, цей ключ може бути підробним! Уважно перевірте, чи "
+"точно вказано адресу електронної пошти. Якщо ключ є підозріливим, "
+"скористайтеся командою\n"
+"  %s\n"
+"для позначення ключа як помилкового.\n"
 msgstr[2] ""
+"Попередження: якщо вам здається, що у вас було понад %ld повідомлень, "
+"підписане цим ключем, цей ключ може бути підробним! Уважно перевірте, чи "
+"точно вказано адресу електронної пошти. Якщо ключ є підозріливим, "
+"скористайтеся командою\n"
+"  %s\n"
+"для позначення ключа як помилкового.\n"
 
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
+#, c-format
 msgid "error opening TOFU database: %s\n"
-msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ð½Ð°Ð´Ñ\81иланнÑ\8f Ð´Ð°Ð½Ð¸Ñ\85: %s\n"
+msgstr "помилка Ð¿Ñ\96д Ñ\87аÑ\81 Ñ\81пÑ\80оби Ð²Ñ\96дкÑ\80иÑ\82и Ð±Ð°Ð·Ð¸ Ð´Ð°Ð½Ð¸Ñ\85 TOFU: %s\n"
 
 #, c-format
 msgid "'%s' is not a valid long keyID\n"
@@ -5879,27 +5834,29 @@ msgstr "потреби у перевірці trustdb на основі моде
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "потреби у оновленні trustdb на основі моделі довіри «%s» немає\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "відкритий ключ %s не знайдено: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "будь ласка, скористайтеся параметром --check-trustdb\n"
 
 msgid "checking the trustdb\n"
 msgstr "перевірка trustdb\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys processed so far\n"
+#, c-format
 msgid "%d key processed"
 msgid_plural "%d keys processed"
-msgstr[0] "оброблено %lu ключів\n"
-msgstr[1] "оброблено %lu ключів\n"
-msgstr[2] "оброблено %lu ключів\n"
+msgstr[0] "оброблено %d ключ"
+msgstr[1] "оброблено %d ключі"
+msgstr[2] "оброблено %d ключів"
 
-#, fuzzy, c-format
-#| msgid "%d keys processed (%d validity counts cleared)\n"
+#, c-format
 msgid " (%d validity count cleared)\n"
 msgid_plural " (%d validity counts cleared)\n"
-msgstr[0] "Оброблено %d ключів (очищено %d значень чинності)\n"
-msgstr[1] "Оброблено %d ключів (очищено %d значень чинності)\n"
-msgstr[2] "Оброблено %d ключів (очищено %d значень чинності)\n"
+msgstr[0] " (очищено %d значення чинності)\n"
+msgstr[1] " (очищено %d значення чинності)\n"
+msgstr[2] " (очищено %d значень чинності)\n"
 
 msgid "no ultimately trusted keys found\n"
 msgstr "не знайдено ключів з необмеженою довірою\n"
@@ -5957,6 +5914,11 @@ msgstr "[невідома]"
 msgid "[  undef ]"
 msgstr "[не визн.]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "ніколи"
+
 msgid "[marginal]"
 msgstr "[неповна ]"
 
@@ -6117,16 +6079,15 @@ msgstr "помилка отримання стану CHV з картки\n"
 msgid "card is permanently locked!\n"
 msgstr "картку заблоковано!\n"
 
-#, fuzzy, c-format
-#| msgid "%d Admin PIN attempts remaining before card is permanently locked\n"
+#, c-format
 msgid "%d Admin PIN attempt remaining before card is permanently locked\n"
 msgid_plural ""
 "%d Admin PIN attempts remaining before card is permanently locked\n"
 msgstr[0] ""
-"залиÑ\88илоÑ\81Ñ\8f %d Ñ\81пÑ\80об визначення адміністративного пінкоду перед тим, як "
+"залиÑ\88илаÑ\81Ñ\8f %d Ñ\81пÑ\80оба визначення адміністративного пінкоду перед тим, як "
 "картку буде остаточно заблоковано\n"
 msgstr[1] ""
-"залишилося %d спроб визначення адміністративного пінкоду перед тим, як "
+"залишилося %d спроби визначення адміністративного пінкоду перед тим, як "
 "картку буде остаточно заблоковано\n"
 msgstr[2] ""
 "залишилося %d спроб визначення адміністративного пінкоду перед тим, як "
@@ -6209,12 +6170,11 @@ msgstr "зачекайте на завершення створення ключ
 msgid "generating key failed\n"
 msgstr "помилка під час створення ключа\n"
 
-#, fuzzy, c-format
-#| msgid "key generation completed (%d seconds)\n"
+#, c-format
 msgid "key generation completed (%d second)\n"
 msgid_plural "key generation completed (%d seconds)\n"
-msgstr[0] "створення ключа завершено (за %d секунд)\n"
-msgstr[1] "створення ключа завершено (за %d секунд)\n"
+msgstr[0] "створення ключа завершено (за %d секунду)\n"
+msgstr[1] "створення ключа завершено (за %d секунди)\n"
 msgstr[2] "створення ключа завершено (за %d секунд)\n"
 
 msgid "invalid structure of OpenPGP card (DO 0x93)\n"
@@ -8338,10 +8298,8 @@ msgstr "|N|завершувати строк дії паролів за вказ
 msgid "do not allow the reuse of old passphrases"
 msgstr "не дозволяти повторне використання старих паролів"
 
-#, fuzzy
-#| msgid "|N|set LDAP timeout to N seconds"
 msgid "|N|set the Pinentry timeout to N seconds"
-msgstr "|N|встановити вказаний час очікування даних від LDAP"
+msgstr "|N|встановити вказаний час очікування Pinentry у секундах"
 
 msgid "|NAME|use NAME as default secret key"
 msgstr "|NAME|використовувати вказаний типовий закритий ключ"
index 3d5f8bc..034ee5c 100644 (file)
@@ -473,6 +473,10 @@ msgid "error binding socket to '%s': %s\n"
 msgstr "在‘%s’中寻找信任度记录时出错:%s\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "警告:扩展模块‘%s’权限不安全\n"
+
+#, fuzzy, c-format
 msgid "listen() failed: %s\n"
 msgstr "更新失败:%s\n"
 
@@ -491,10 +495,6 @@ msgid "directory '%s' created\n"
 msgstr "已创建目录‘%s’\n"
 
 #, fuzzy, c-format
-msgid "can't set permissions of '%s': %s\n"
-msgstr "警告:扩展模块‘%s’权限不安全\n"
-
-#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fstat(%d) 在 %s 中出错:%s\n"
 
@@ -1924,13 +1924,13 @@ msgstr "更改密码"
 msgid "export keys"
 msgstr "导出密钥"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "把密钥导出到某个公钥服务器上"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "从公钥服务器上导入密钥"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "在公钥服务器上搜寻密钥"
 
 msgid "update all keys from a keyserver"
@@ -2531,6 +2531,9 @@ msgstr "把时间戳矛盾仅视为警告"
 msgid "|FD|write status info to this FD"
 msgstr "|FD|把状态信息写入文件描述符 FD"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "用法:gpgv [选项] [文件] (用 -h 求助)"
 
@@ -3948,6 +3951,11 @@ msgstr ""
 msgid "No key with this keygrip\n"
 msgstr "没有索引为 %d 的子钥\n"
 
+#, fuzzy, c-format
+#| msgid "rounded up to %u bits\n"
+msgid "rounded to %u bits\n"
+msgstr "舍入到 %u 位\n"
+
 #, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "%s 密钥长度应在 %u 位与 %u 位之间。\n"
@@ -3964,11 +3972,6 @@ msgstr "您想要用多大的密钥尺寸?(%u)"
 msgid "Requested keysize is %u bits\n"
 msgstr "您所要求的密钥尺寸是 %u 位\n"
 
-#, fuzzy, c-format
-#| msgid "rounded up to %u bits\n"
-msgid "rounded to %u bits\n"
-msgstr "舍入到 %u 位\n"
-
 #, fuzzy
 #| msgid "Please select what kind of key you want:\n"
 msgid "Please select which elliptic curve you want:\n"
@@ -5599,14 +5602,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "读取‘%s’时出错:%s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "找不到公钥 %s:%s\n"
-
-#, fuzzy, c-format
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "读取‘%s’时出错:%s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5685,14 +5680,14 @@ msgstr[0] ""
 msgstr[1] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5700,6 +5695,10 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "读取‘%s’时出错:%s\n"
+
+#, fuzzy, c-format
 msgid "error changing TOFU policy: %s\n"
 msgstr "生成密码的时候发生错误:%s\n"
 
@@ -5855,6 +5854,10 @@ msgstr "使用‘%s’信任模型时不需要检查信任度数据库\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "使用‘%s’信任模型时不需要更新信任度数据库\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "找不到公钥 %s:%s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "请执行一次 --check-trustdb\n"
 
@@ -5932,6 +5935,11 @@ msgstr "[ 未知 ]"
 msgid "[  undef ]"
 msgstr "[未定义]"
 
+#, fuzzy
+#| msgid "never"
+msgid "[  never ]"
+msgstr "从不"
+
 msgid "[marginal]"
 msgstr "[ 勉强 ]"
 
index 22aebfa..984ef55 100644 (file)
@@ -440,6 +440,11 @@ msgstr "為 socket 取得 nonce 時出錯\n"
 msgid "error binding socket to '%s': %s\n"
 msgstr "綁定 socket 至 '%s' 時出錯: %s\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "警告: %s 的權限 \"%s\" 並不安全\n"
+
 #, c-format
 msgid "listen() failed: %s\n"
 msgstr "listen() 失敗: %s\n"
@@ -456,11 +461,6 @@ msgstr "無法建立目錄 '%s': %s\n"
 msgid "directory '%s' created\n"
 msgstr "目錄 '%s' 已建立\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
-msgid "can't set permissions of '%s': %s\n"
-msgstr "警告: %s 的權限 \"%s\" 並不安全\n"
-
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "'%s' 的 stat() 失敗: %s\n"
@@ -1823,13 +1823,13 @@ msgstr "更改密語"
 msgid "export keys"
 msgstr "匯出金鑰"
 
-msgid "export keys to a key server"
+msgid "export keys to a keyserver"
 msgstr "把金鑰匯出至金鑰伺服器"
 
-msgid "import keys from a key server"
+msgid "import keys from a keyserver"
 msgstr "從金鑰伺服器匯入金鑰"
 
-msgid "search for keys on a key server"
+msgid "search for keys on a keyserver"
 msgstr "在金鑰伺服器上搜尋金鑰"
 
 msgid "update all keys from a keyserver"
@@ -2388,6 +2388,9 @@ msgstr "僅把時間戳印矛盾視為警告"
 msgid "|FD|write status info to this FD"
 msgstr "|檔案描述|把狀態資訊寫入此指定檔案描述"
 
+msgid "|ALGO|reject signatures made with ALGO"
+msgstr ""
+
 msgid "Usage: gpgv [options] [files] (-h for help)"
 msgstr "用法: gpgv [選項] [檔案] (或用 -h 求助)"
 
@@ -3774,6 +3777,10 @@ msgid "No key with this keygrip\n"
 msgstr "沒有金鑰有此金鑰鑰柄\n"
 
 #, c-format
+msgid "rounded to %u bits\n"
+msgstr "加大到 %u 位元\n"
+
+#, c-format
 msgid "%s keys may be between %u and %u bits long.\n"
 msgstr "%s 金鑰的長度可能介於 %u 位元和 %u 位元之間.\n"
 
@@ -3789,10 +3796,6 @@ msgstr "你想要用多大的金鑰尺寸? (%u) "
 msgid "Requested keysize is %u bits\n"
 msgstr "你所要求的金鑰尺寸是 %u 位元\n"
 
-#, c-format
-msgid "rounded to %u bits\n"
-msgstr "加大到 %u 位元\n"
-
 msgid "Please select which elliptic curve you want:\n"
 msgstr "請選擇你要使用的橢圓曲線:\n"
 
@@ -5390,15 +5393,6 @@ msgid "error updating TOFU database: %s\n"
 msgstr "送出資料時出錯: %s\n"
 
 #, c-format
-msgid "public key %s not found: %s\n"
-msgstr "找不到公鑰 %s: %s\n"
-
-#, fuzzy, c-format
-#| msgid "error setting OCSP target: %s\n"
-msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "設定 OCSP 目標時出錯: %s\n"
-
-#, c-format
 msgid "The binding %s is NOT known."
 msgstr ""
 
@@ -5473,14 +5467,14 @@ msgid_plural " over the past %ld months."
 msgstr[0] ""
 
 #. TRANSLATORS: Please translate the text found in the source
-#. file below.  We don't directly internationalize that text
-#. so that we can tweak it without breaking translations.
+#. * file below.  We don't directly internationalize that text so
+#. * that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
-#. version of the hotkey) for each of the five choices.  If
-#. there is only one choice in your language, repeat it.
+#. version of the hotkey) for each of the five choices.  If
+#. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
 msgstr ""
 
@@ -5488,6 +5482,11 @@ msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "error setting OCSP target: %s\n"
+msgid "error setting TOFU binding's trust level to %s\n"
+msgstr "設定 OCSP 目標時出錯: %s\n"
+
+#, fuzzy, c-format
 #| msgid "error creating a pipe: %s\n"
 msgid "error changing TOFU policy: %s\n"
 msgstr "建立管道時出錯: %s\n"
@@ -5635,6 +5634,10 @@ msgstr "在 '%s' 信任模型中並不需要檢查信任資料庫\n"
 msgid "no need for a trustdb update with '%s' trust model\n"
 msgstr "在 '%s' 信任模型中並不需要更新信任資料庫\n"
 
+#, c-format
+msgid "public key %s not found: %s\n"
+msgstr "找不到公鑰 %s: %s\n"
+
 msgid "please do a --check-trustdb\n"
 msgstr "請做一次 --check-trustdb\n"
 
@@ -5715,6 +5718,11 @@ msgstr "未知"
 msgid "[  undef ]"
 msgstr ""
 
+#, fuzzy
+#| msgid "never     "
+msgid "[  never ]"
+msgstr "永遠不過期"
+
 msgid "[marginal]"
 msgstr ""
 
index 72ff132..a4a2ba0 100644 (file)
@@ -2281,7 +2281,7 @@ update_reader_status_file (int set_card_removed_flag)
             depends on how client sessions will associate the reader
             status with their session.  */
           snprintf (templ, sizeof templ, "reader_%d.status", vr->slot);
-          fname = make_filename (opt.homedir, templ, NULL );
+          fname = make_filename (gnupg_homedir (), templ, NULL );
           fp = fopen (fname, "w");
           if (fp)
             {
@@ -2300,7 +2300,7 @@ update_reader_status_file (int set_card_removed_flag)
             char *homestr, *envstr;
             gpg_error_t err;
 
-            homestr = make_filename (opt.homedir, NULL);
+            homestr = make_filename (gnupg_homedir (), NULL);
             if (gpgrt_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0)
               log_error ("out of core while building environment\n");
             else
@@ -2323,7 +2323,7 @@ update_reader_status_file (int set_card_removed_flag)
                            (status & 2)? "PRESENT": "NOCARD");
                 args[8] = NULL;
 
-                fname = make_filename (opt.homedir, "scd-event", NULL);
+                fname = make_filename (gnupg_homedir (), "scd-event", NULL);
                 err = gnupg_spawn_process_detached (fname, args, envs);
                 if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
                   log_error ("failed to run event handler '%s': %s\n",
index e8218ca..9c11cad 100644 (file)
@@ -371,18 +371,10 @@ cleanup (void)
   if (socket_name && *socket_name)
     {
       char *name;
-      char *p;
 
       name = redir_socket_name? redir_socket_name : socket_name;
 
       gnupg_remove (name);
-      p = strrchr (name, '/');
-      if (p)
-        {
-          *p = 0;
-          rmdir (name);
-          *p = '/';
-        }
       *socket_name = 0;
     }
 }
@@ -463,8 +455,6 @@ main (int argc, char **argv )
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
 
-  opt.homedir = default_homedir ();
-
   /* Check whether we have a config file on the commandline */
   orig_argc = argc;
   orig_argv = argv;
@@ -484,7 +474,7 @@ 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;
+          gnupg_set_homedir (pargs.r.ret_str);
     }
 
   /* initialize the secure memory. */
@@ -497,7 +487,7 @@ main (int argc, char **argv )
 
 
   if (default_config)
-    configname = make_filename (opt.homedir, SCDAEMON_NAME EXTSEP_S "conf",
+    configname = make_filename (gnupg_homedir (), SCDAEMON_NAME EXTSEP_S "conf",
                                 NULL );
 
 
@@ -582,7 +572,7 @@ main (int argc, char **argv )
         case oNoGreeting: nogreeting = 1; break;
         case oNoVerbose: opt.verbose = 0; break;
         case oNoOptions: break; /* no-options */
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oNoDetach: nodetach = 1; break;
         case oLogFile: logfile = pargs.r.ret_str; break;
         case oCsh: csh_style = 1; break;
@@ -674,8 +664,8 @@ main (int argc, char **argv )
       if (config_filename)
        filename = xstrdup (config_filename);
       else
-        filename = make_filename (opt.homedir, SCDAEMON_NAME EXTSEP_S "conf",
-                                  NULL);
+        filename = make_filename (gnupg_homedir (),
+                                  SCDAEMON_NAME EXTSEP_S "conf", NULL);
       filename_esc = percent_escape (filename, NULL);
 
       es_printf ("%s-%s.conf:%lu:\"%s\n",
@@ -1044,7 +1034,7 @@ create_socket_name (char *standard_name)
 {
   char *name;
 
-  name = make_filename (opt.homedir, standard_name, NULL);
+  name = make_filename (gnupg_socketdir (), standard_name, NULL);
   if (strchr (name, PATHSEP_C))
     {
       log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
@@ -1122,6 +1112,10 @@ create_server_socket (const char *name, char **r_redir_name,
       scd_exit (2);
     }
 
+  if (gnupg_chmod (unaddr->sun_path, "-rwx"))
+    log_error (_("can't set permissions of '%s': %s\n"),
+               unaddr->sun_path, strerror (errno));
+
   if (listen (FD2INT(fd), 5 ) == -1)
     {
       log_error (_("listen() failed: %s\n"),
index 1a95ba7..448cb84 100644 (file)
@@ -51,7 +51,6 @@ struct
   int quiet;          /* Be as quiet as possible. */
   int dry_run;        /* Don't change any persistent data. */
   int batch;          /* Batch mode. */
-  const char *homedir;      /* Configuration directory name. */
   const char *ctapi_driver; /* Library to access the ctAPI. */
   const char *pcsc_driver;  /* Library to access the PC/SC system. */
   const char *reader_port;  /* NULL or reder port to use. */
index 8c1c727..c7facbb 100644 (file)
@@ -133,7 +133,6 @@ start_agent (ctrl_t ctrl)
     {
       rc = start_new_gpg_agent (&agent_ctx,
                                 GPG_ERR_SOURCE_DEFAULT,
-                                opt.homedir,
                                 opt.agent_program,
                                 opt.lc_ctype, opt.lc_messages,
                                 opt.session_env,
index 881c484..7e26c3a 100644 (file)
@@ -248,7 +248,7 @@ start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
      to take care of the implicit option sending caching. */
 
   err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT,
-                           opt.homedir, opt.dirmngr_program,
+                           opt.dirmngr_program,
                            opt.autostart, opt.verbose, DBG_IPC,
                            gpgsm_status2, ctrl);
   if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
index fc6d1c7..9b7dd4b 100644 (file)
@@ -211,8 +211,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aKeygen, "gen-key", N_("generate a new key pair")),
   ARGPARSE_c (aDeleteKey, "delete-keys",
               N_("remove keys from the public keyring")),
-/*ARGPARSE_c (aSendKeys, "send-keys", N_("export keys to a key server")),*/
-/*ARGPARSE_c (aRecvKeys, "recv-keys", N_("import keys from a key server")),*/
+/*ARGPARSE_c (aSendKeys, "send-keys", N_("export keys to a keyserver")),*/
+/*ARGPARSE_c (aRecvKeys, "recv-keys", N_("import keys from a keyserver")),*/
   ARGPARSE_c (aImport, "import", N_("import certificates")),
   ARGPARSE_c (aExport, "export", N_("export certificates")),
 
@@ -581,7 +581,7 @@ my_strusage( int level )
       break;
 
     case 31: p = "\nHome: "; break;
-    case 32: p = opt.homedir; break;
+    case 32: p = gnupg_homedir (); break;
     case 33: p = _("\nSupported algorithms:\n"); break;
     case 34:
       if (!ciphers)
@@ -964,8 +964,6 @@ main ( int argc, char **argv)
      remember to update the Gpgconflist entry as well.  */
   opt.def_cipher_algoid = DEFAULT_CIPHER_ALGO;
 
-  opt.homedir = default_homedir ();
-
 
   /* First check whether we have a config file on the commandline */
   orig_argc = argc;
@@ -989,7 +987,7 @@ main ( int argc, char **argv)
           opt.no_homedir_creation = 1;
         }
       else if (pargs.r_opt == oHomedir)
-        opt.homedir = pargs.r.ret_str;
+        gnupg_set_homedir (pargs.r.ret_str);
       else if (pargs.r_opt == aCallProtectTool)
         break; /* This break makes sure that --version and --help are
                   passed to the protect-tool. */
@@ -1024,9 +1022,10 @@ main ( int argc, char **argv)
 
   /* Set the default option file */
   if (default_config )
-    configname = make_filename (opt.homedir, GPGSM_NAME EXTSEP_S "conf", NULL);
+    configname = make_filename (gnupg_homedir (),
+                                GPGSM_NAME EXTSEP_S "conf", NULL);
   /* Set the default policy file */
-  opt.policy_file = make_filename (opt.homedir, "policies.txt", NULL);
+  opt.policy_file = make_filename (gnupg_homedir (), "policies.txt", NULL);
 
   argc        = orig_argc;
   argv        = orig_argv;
@@ -1304,7 +1303,7 @@ main ( int argc, char **argv)
            }
           break;
         case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
 
         case oDisplay:
@@ -1468,7 +1467,7 @@ main ( int argc, char **argv)
   configname = NULL;
 
   if (!opt.config_filename)
-    opt.config_filename = make_filename (opt.homedir,
+    opt.config_filename = make_filename (gnupg_homedir (),
                                          GPGSM_NAME EXTSEP_S "conf",
                                          NULL);
 
@@ -1560,6 +1559,8 @@ main ( int argc, char **argv)
   else if (!strcmp (opt.def_cipher_algoid, "AES")
            || !strcmp (opt.def_cipher_algoid, "AES128"))
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.2";
+  else if (!strcmp (opt.def_cipher_algoid, "AES192") )
+    opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.22";
   else if (!strcmp (opt.def_cipher_algoid, "AES256") )
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.42";
   else if (!strcmp (opt.def_cipher_algoid, "SERPENT")
@@ -1567,7 +1568,7 @@ main ( int argc, char **argv)
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.2";
   else if (!strcmp (opt.def_cipher_algoid, "SERPENT192") )
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.22";
-  else if (!strcmp (opt.def_cipher_algoid, "SERPENT192") )
+  else if (!strcmp (opt.def_cipher_algoid, "SERPENT256") )
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.42";
   else if (!strcmp (opt.def_cipher_algoid, "SEED") )
     opt.def_cipher_algoid = "1.2.410.200004.1.4";
@@ -1605,7 +1606,7 @@ main ( int argc, char **argv)
   /* Set the random seed file. */
   if (use_random_seed)
     {
-      char *p = make_filename (opt.homedir, "random_seed", NULL);
+      char *p = make_filename (gnupg_homedir (), "random_seed", NULL);
       gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
       xfree(p);
     }
index 5aad4b1..9751df4 100644 (file)
@@ -61,7 +61,6 @@ struct
   int dry_run;      /* don't change any persistent data */
   int no_homedir_creation;
 
-  const char *homedir;         /* Configuration directory name */
   const char *config_filename; /* Name of the used config file. */
   const char *agent_program;
 
index 495eb49..8a1efd4 100644 (file)
@@ -287,7 +287,7 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
       if (strchr(resname, DIRSEP_C) )
         filename = make_filename (resname, NULL);
       else
-        filename = make_filename (opt.homedir, resname, NULL);
+        filename = make_filename (gnupg_homedir (), resname, NULL);
     }
   else
     filename = xstrdup (resname);
index a43ff34..8b4a29c 100644 (file)
@@ -1308,7 +1308,7 @@ gpgsm_server (certlist_t default_recplist)
     }
   if (opt.verbose || opt.debug)
     {
-      char *tmp = NULL;
+      char *tmp;
 
       /* Fixme: Use the really used socket name.  */
       if (asprintf (&tmp,
@@ -1316,7 +1316,7 @@ gpgsm_server (certlist_t default_recplist)
                     "Config: %s\n"
                     "DirmngrInfo: %s\n"
                     "%s",
-                    opt.homedir,
+                    gnupg_homedir (),
                     opt.config_filename,
                     (dirmngr_user_socket_name ()
                      ? dirmngr_user_socket_name ()
index bab0b7d..bb1047d 100644 (file)
@@ -57,6 +57,7 @@ TESTS = version.test mds.test \
        import.test ecc.test 4gb-packet.test \
        $(sqlite3_dependent_tests) \
        gpgtar.test use-exact-key.test default-key.test \
+       export.test \
        finish.test
 
 
@@ -123,7 +124,8 @@ CLEANFILES = prepared.stamp x y yy z out err  $(data_files) \
             *.test.log gpg_dearmor gpg.conf gpg-agent.conf S.gpg-agent \
             pubring.gpg pubring.gpg~ pubring.kbx pubring.kbx~ \
             secring.gpg pubring.pkr secring.skr \
-            gnupg-test.stop random_seed gpg-agent.log tofu.db
+            gnupg-test.stop random_seed gpg-agent.log tofu.db \
+            passphrases
 
 clean-local:
        -rm -rf private-keys-v1.d openpgp-revocs.d tofu.d gpgtar.d
diff --git a/tests/openpgp/export.test b/tests/openpgp/export.test
new file mode 100755 (executable)
index 0000000..9776760
--- /dev/null
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+. $srcdir/defs.inc || exit 3
+
+check_exported_public_key()
+{
+    $GPG --list-packets $1 >$1.packets
+    grep '^:public key packet:' $1.packets >/dev/null
+    grep "^    keyid: .*$KEY$" $1.packets >/dev/null
+    grep '^:user ID packet:' $1.packets >/dev/null
+    grep "^:signature packet:.*keyid.*$KEY" $1.packets >/dev/null
+    rm $1.packets
+}
+
+check_armored_public_key()
+{
+    grep '^-----BEGIN PGP PUBLIC KEY BLOCK-----$' $1 >/dev/null
+    grep '^-----END PGP PUBLIC KEY BLOCK-----$' $1 >/dev/null
+    check_exported_public_key $1
+}
+
+check_exported_private_key()
+{
+    $GPG --list-packets $1 >$1.packets
+    grep '^:secret key packet:' $1.packets >/dev/null
+    grep "^    keyid: .*$KEY$" $1.packets >/dev/null
+    grep '^:user ID packet:' $1.packets >/dev/null
+    grep "^:signature packet:.*keyid.*$KEY" $1.packets >/dev/null
+    rm $1.packets
+}
+
+check_armored_private_key()
+{
+    grep '^-----BEGIN PGP PRIVATE KEY BLOCK-----$' $1 >/dev/null
+    grep '^-----END PGP PRIVATE KEY BLOCK-----$' $1 >/dev/null
+    check_exported_private_key $1
+}
+
+logfile="`pwd`/pinentry.log"
+ppfile="`pwd`/passphrases"
+rm -f -- $logfile $ppfile
+touch $ppfile
+
+prepare_passphrase()
+{
+    echo $* >>$ppfile
+}
+
+prepare_passphrase_confirm()
+{
+    echo "fake-entry being started to CONFIRM the weak phrase" >>$ppfile
+}
+
+assert_passphrases_consumed()
+{
+    if test -s $ppfile; then
+        echo "Expected $ppfile to be empty, but these are enqueued:" >&2
+        cat "$ppfile" >&2
+        exit 1
+    fi
+    rm -f -- $logfile
+}
+
+export PINENTRY_USER_DATA="--logfile=$logfile --passphrasefile=$ppfile"
+
+info "Checking key export."
+for KEY in D74C5F22 C40FDECF ECABF51D
+do
+    progress $KEY
+
+    $GPG --export $KEY >$KEY.public
+    check_exported_public_key $KEY.public
+    rm $KEY.public
+
+    $GPG --armor --export $KEY >$KEY.public
+    check_armored_public_key $KEY.public
+    rm $KEY.public
+
+    # test without --armor:
+
+    if [ $KEY = D74C5F22 ]; then
+        # Key D74C5F22 is protected by a passphrase.  Prepare this
+        # one.  Currently, GnuPG does not ask for an export passphrase
+        # in this case.
+        prepare_passphrase "$usrpass1"
+    fi
+
+    $GPG --export-secret-keys $KEY >$KEY.private
+    check_exported_private_key $KEY.private
+    rm $KEY.private
+
+    assert_passphrases_consumed
+
+    # test with --armor:
+
+    if [ $KEY = D74C5F22 ]; then
+        # Key D74C5F22 is protected by a passphrase.  Prepare this
+        # one.  Currently, GnuPG does not ask for an export passphrase
+        # in this case.
+        prepare_passphrase "$usrpass1"
+    fi
+
+    $GPG --armor --export-secret-keys $KEY >$KEY.private
+    check_armored_private_key $KEY.private
+    rm $KEY.private
+
+    assert_passphrases_consumed
+done
+
+progress_end
index b8aa848..a651726 100644 (file)
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdarg.h>
+
+FILE *log_stream;
+
+int
+reply (const char *fmt, ...)
+{
+  int result;
+  va_list ap;
+
+  if (log_stream)
+    {
+      fprintf (log_stream, "> ");
+      va_start (ap, fmt);
+      vfprintf (log_stream, fmt, ap);
+      va_end (ap);
+    }
+  va_start (ap, fmt);
+  result = vprintf (fmt, ap);
+  va_end (ap);
+
+  return result;
+}
+
+/* Return the first line from FNAME, removing it from the file.  */
+char *
+get_passphrase (const char *fname)
+{
+  char *passphrase = NULL;
+  size_t fname_len;
+  char *fname_new;
+  FILE *source, *sink;
+  char linebuf[80];
+
+  fname_len = strlen (fname);
+  fname_new = malloc (fname_len + 5);
+  if (fname_new == NULL)
+    {
+      perror ("malloc");
+      exit (1);
+    }
+  snprintf (fname_new, fname_len + 5, "%s.new", fname);
+
+  source = fopen (fname, "r");
+  if (! source)
+    {
+      perror (fname);
+      exit (1);
+    }
+
+  sink = fopen (fname_new, "w");
+  if (! sink)
+    {
+      perror (fname_new);
+      exit (1);
+    }
+
+  while (fgets (linebuf, sizeof linebuf, source))
+    {
+      linebuf[sizeof linebuf - 1] = 0;
+      if (passphrase == NULL)
+        {
+          passphrase = strdup (linebuf);
+          if (passphrase == NULL)
+            {
+              perror ("strdup");
+              exit (1);
+            }
+        }
+      else
+        fputs (linebuf, sink);
+    }
+
+  if (ferror (source))
+    {
+      perror (fname);
+      exit (1);
+    }
+
+  if (ferror (sink))
+    {
+      perror (fname_new);
+      exit (1);
+    }
+
+  fclose (source);
+  fclose (sink);
+  rename (fname_new, fname);
+  return passphrase;
+}
+
+\f
+#define spacep(p)   (*(p) == ' ' || *(p) == '\t')
+
+/* Skip over options in LINE.
+
+   Blanks after the options are also removed.  Options are indicated
+   by two leading dashes followed by a string consisting of non-space
+   characters.  The special option "--" indicates an explicit end of
+   options; all what follows will not be considered an option.  The
+   first no-option string also indicates the end of option parsing. */
+char *
+skip_options (const char *line)
+{
+  while (spacep (line))
+    line++;
+  while (*line == '-' && line[1] == '-')
+    {
+      while (*line && !spacep (line))
+        line++;
+      while (spacep (line))
+        line++;
+    }
+  return (char*) line;
+}
+
+
+/* Return a pointer to the argument of the option with NAME.  If such
+   an option is not given, NULL is returned. */
+char *
+option_value (const char *line, const char *name)
+{
+  char *s;
+  int n = strlen (name);
+
+  s = strstr (line, name);
+  if (s && s >= skip_options (line))
+    return NULL;
+  if (s && (s == line || spacep (s-1))
+      && s[n] && (spacep (s+n) || s[n] == '='))
+    {
+      s += n + 1;
+      s += strspn (s, " ");
+      if (*s && !spacep(s))
+        return s;
+    }
+  return NULL;
+}
 
 int
 main (int argc, char **argv)
 {
-  static char *passphrase;
-  char *p;
+  char *args;
+  char *logfile;
+  char *passphrasefile;
+  char *passphrase;
 
+  /* We get our options via PINENTRY_USER_DATA.  */
   (void) argc, (void) argv;
 
   setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
   setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
 
-  if (!passphrase)
+  args = getenv ("PINENTRY_USER_DATA");
+  if (! args)
+    args = "";
+
+  logfile = option_value (args, "--logfile");
+  if (logfile)
+    {
+      char *p = logfile, more;
+      while (*p && ! spacep (p))
+        p++;
+      more = !! *p;
+      *p = 0;
+      args = more ? p+1 : p;
+
+      log_stream = fopen (logfile, "a");
+      if (! log_stream)
+        {
+          perror (logfile);
+          return 1;
+        }
+    }
+
+  passphrasefile = option_value (args, "--passphrasefile");
+  if (passphrasefile)
     {
-      passphrase = getenv ("PINENTRY_USER_DATA");
-      if (!passphrase)
-        passphrase = "";
-      for (p=passphrase; *p; p++)
-        if (*p == '\r' || *p == '\n')
-          *p = '.';
-      printf ("# Passphrase='%s'\n", passphrase);
+      char *p = passphrasefile, more;
+      while (*p && ! spacep (p))
+        p++;
+      more = !! *p;
+      *p = 0;
+      args = more ? p+1 : p;
+
+      passphrase = get_passphrase (passphrasefile);
+      if (! passphrase)
+        {
+          reply ("# Passphrasefile '%s' is empty.  Terminating.\n",
+                 passphrasefile);
+          return 1;
+        }
+
+      p = passphrase + strlen (passphrase) - 1;
+      if (*p == '\n')
+        *p = 0;
     }
+  else
+    passphrase = skip_options (args);
 
-  printf ("OK - what's up?\n");
+  reply ("# fake-pinentry started.  Passphrase='%s'.\n", passphrase);
+  reply ("OK - what's up?\n");
 
   while (! feof (stdin))
     {
@@ -53,15 +231,23 @@ main (int argc, char **argv)
       if (fgets (buffer, sizeof buffer, stdin) == NULL)
        break;
 
+      if (log_stream)
+        fprintf (log_stream, "< %s", buffer);
+
       if (strncmp (buffer, "GETPIN", 6) == 0)
-       printf ("D %s\nOK\n", passphrase);
+        reply ("D %s\n", passphrase);
       else if (strncmp (buffer, "BYE", 3) == 0)
        {
-         printf ("OK\n");
+         reply ("OK\n");
          break;
        }
-      else
-       printf ("OK\n");
+
+      reply ("OK\n");
     }
+
+  reply ("# Connection terminated.\n");
+  if (log_stream)
+    fclose (log_stream);
+
   return 0;
 }
index 39c0f9c..d43ede8 100644 (file)
@@ -17,7 +17,7 @@
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 EXTRA_DIST = \
-       Manifest watchgnupg.c \
+       Manifest watchgnupg.c no-libgcrypt.c \
        addgnupghome applygnupgdefaults \
        lspgpot mail-signed-keys convert-from-106 sockprox.c \
        ccidmon.c ChangeLog-2011 gpg-connect-agent-w32info.rc
@@ -91,12 +91,12 @@ gpgsplit_LDADD = $(common_libs) \
                 $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
                 $(ZLIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV)
 
-gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c no-libgcrypt.c
+gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c
 
 # common sucks in gpg-error, will they, nil they (some compilers
 # do not eliminate the supposed-to-be-unused-inline-functions).
 gpgconf_LDADD = $(maybe_commonpth_libs) $(opt_libassuan_libs) \
-                $(LIBINTL) $(GPG_ERROR_LIBS) $(NETLIBS) \
+                $(LIBINTL) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \
                $(LIBICONV) $(W32SOCKLIBS)
 gpgconf_LDFLAGS = $(extra_bin_ldflags)
 
@@ -111,10 +111,11 @@ symcryptrun_LDADD = $(LIBUTIL_LIBS) $(common_libs) $(pwquery_libs) \
 watchgnupg_SOURCES = watchgnupg.c
 watchgnupg_LDADD = $(NETLIBS)
 
-gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c
-# FIXME: remove PTH_LIBS (why do we need them at all?)
+gpg_connect_agent_SOURCES = gpg-connect-agent.c
+# FIXME: remove NPTH_LIBS (why do we need them at all?)
 gpg_connect_agent_LDADD = ../common/libgpgrl.a $(common_libs) \
-                         $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
+                         $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
+                          $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
                           $(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
                           $(resource_objs)
 
@@ -130,10 +131,9 @@ gpgtar_SOURCES = \
        gpgtar.c gpgtar.h \
        gpgtar-create.c \
        gpgtar-extract.c \
-       gpgtar-list.c \
-       no-libgcrypt.c
+       gpgtar-list.c
 gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS)
-gpgtar_LDADD = $(libcommon) $(GPG_ERROR_LIBS) \
+gpgtar_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
                $(LIBINTL) $(NETLIBS) $(LIBICONV) $(W32SOCKLIBS)
 
 
index fbf30a2..37283a1 100644 (file)
@@ -181,8 +181,6 @@ main (int argc, char **argv )
   setup_libgcrypt_logging ();
   gcry_control (GCRYCTL_INIT_SECMEM, 4096, 0);
 
-  opt.homedir = default_homedir ();
-
   pargs.argc = &argc;
   pargs.argv = &argv;
   pargs.flags=  1;  /* (do not remove the args) */
@@ -191,7 +189,7 @@ main (int argc, char **argv )
       switch (pargs.r_opt)
         {
         case oVerbose: opt.verbose++; break;
-        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oCheck: opt.checkonly = 1; break;
         case oNull: opt.null = 1; break;
 
index 2e00b8f..1cd554f 100644 (file)
@@ -209,7 +209,7 @@ my_strusage( int level )
             "Connect to a running agent and send commands\n");
       break;
     case 31: p = "\nHome: "; break;
-    case 32: p = opt.homedir; break;
+    case 32: p = gnupg_homedir (); break;
     case 33: p = "\n"; break;
 
     default: p = NULL; break;
@@ -555,7 +555,7 @@ get_var_ext (const char *name)
             log_error ("getcwd failed: %s\n", strerror (errno));
         }
       else if (!strcmp (s, "homedir"))
-        result = make_filename (opt.homedir, NULL);
+        result = xstrdup (gnupg_homedir ());
       else if (!strcmp (s, "sysconfdir"))
         result = xstrdup (gnupg_sysconfdir ());
       else if (!strcmp (s, "bindir"))
@@ -1181,7 +1181,6 @@ main (int argc, char **argv)
   assuan_set_gpg_err_source (0);
 
 
-  opt.homedir = default_homedir ();
   opt.autostart = 1;
   opt.connect_flags = 1;
 
@@ -1196,7 +1195,7 @@ main (int argc, char **argv)
        case oQuiet:     opt.quiet = 1; break;
         case oVerbose:   opt.verbose++; break;
         case oNoVerbose: opt.verbose = 0; break;
-        case oHomedir:   opt.homedir = pargs.r.ret_str; break;
+        case oHomedir:   gnupg_set_homedir (pargs.r.ret_str); break;
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
         case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str;  break;
         case oNoAutostart:    opt.autostart = 0; break;
@@ -1225,7 +1224,7 @@ main (int argc, char **argv)
        in particular handy on Windows. */
   if (opt.use_uiserver)
     {
-      opt.raw_socket = make_absfilename (opt.homedir, "S.uiserver", NULL);
+      opt.raw_socket = make_absfilename (gnupg_homedir (), "S.uiserver", NULL);
     }
 
   /* Print a warning if an argument looks like an option.  */
@@ -2209,7 +2208,6 @@ start_agent (void)
   if (opt.use_dirmngr)
     err = start_new_dirmngr (&ctx,
                              GPG_ERR_SOURCE_DEFAULT,
-                             opt.homedir,
                              opt.dirmngr_program,
                              opt.autostart,
                              !opt.quiet, 0,
@@ -2217,7 +2215,6 @@ start_agent (void)
   else
     err = start_new_gpg_agent (&ctx,
                                GPG_ERR_SOURCE_DEFAULT,
-                               opt.homedir,
                                opt.agent_program,
                                NULL, NULL,
                                session_env,
index 4dd10a4..3d456a9 100644 (file)
@@ -1626,7 +1626,7 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
 
   result = 0;
   errlines = NULL;
-  err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT, NULL, 0,
+  err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
                              NULL, NULL, &errfp, &pid);
   if (err)
     result |= 1; /* Program could not be run.  */
@@ -1965,7 +1965,7 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
   argv[0] = "--gpgconf-list";
   argv[1] = NULL;
 
-  err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT, NULL, 0,
+  err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
                              NULL, &outfp, NULL, &pid);
   if (err)
     {
index 180c88a..2b177e2 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "gpgconf.h"
 #include "i18n.h"
@@ -53,6 +54,8 @@ enum cmd_and_opt_values
     aListDirs,
     aLaunch,
     aKill,
+    aCreateSocketDir,
+    aRemoveSocketDir,
     aReload
   };
 
@@ -78,6 +81,8 @@ static ARGPARSE_OPTS opts[] =
     { aReload,        "reload", 256, N_("reload all or a given component")},
     { aLaunch,        "launch", 256, N_("launch a given component")},
     { aKill,          "kill", 256,   N_("kill a given component")},
+    { aCreateSocketDir, "create-socketdir", 256, "@"},
+    { aRemoveSocketDir, "remove-socketdir", 256, "@"},
 
     { 301, NULL, 0, N_("@\nOptions:\n ") },
 
@@ -87,6 +92,7 @@ static ARGPARSE_OPTS opts[] =
     { oDryRun, "dry-run",   0, N_("do not make any changes") },
     { oRuntime, "runtime",  0, N_("activate changes at runtime, if possible") },
     /* hidden options */
+    { oHomedir, "homedir", 2, "@" },
     { oNoVerbose, "no-verbose",  0, "@"},
     {0}
   };
@@ -176,6 +182,7 @@ main (int argc, char **argv)
          break;
         case oVerbose:   opt.verbose++; break;
         case oNoVerbose: opt.verbose = 0; break;
+        case oHomedir:   gnupg_set_homedir (pargs.r.ret_str); break;
 
        case aListDirs:
         case aListComponents:
@@ -189,6 +196,8 @@ main (int argc, char **argv)
         case aReload:
         case aLaunch:
         case aKill:
+        case aCreateSocketDir:
+        case aRemoveSocketDir:
          cmd = pargs.r_opt;
          break;
 
@@ -375,18 +384,77 @@ main (int argc, char **argv)
         }
 
       {
-        char *tmp = make_filename (default_homedir (),
+        char *tmp = make_filename (gnupg_socketdir (),
                                    GPG_AGENT_SOCK_NAME, NULL);
         es_fprintf (outfp, "agent-socket:%s\n", gc_percent_escape (tmp));
         xfree (tmp);
       }
       {
-        /* We need to use make_filename to expand a possible "~/".  */
-        char *tmp = make_filename (default_homedir (), NULL);
+        char *tmp = xstrdup (gnupg_homedir ());
         es_fprintf (outfp, "homedir:%s\n", gc_percent_escape (tmp));
         xfree (tmp);
       }
       break;
+
+    case aCreateSocketDir:
+      {
+        char *socketdir;
+        unsigned int flags;
+
+        /* Make sure that the top /run/user/UID/gnupg dir has been
+         * created.  */
+        gnupg_socketdir ();
+
+        /* Check the /var/run dir.  */
+        socketdir = _gnupg_socketdir_internal (1, &flags);
+        if ((flags & 64) && !opt.dry_run)
+          {
+            /* No sub dir - create it. */
+            if (gnupg_mkdir (socketdir, "-rwx"))
+              gc_error (1, errno, "error creating '%s'", socketdir);
+            /* Try again.  */
+            socketdir = _gnupg_socketdir_internal (1, &flags);
+          }
+
+        /* Give some info.  */
+        if ( (flags & ~32) || opt.verbose || opt.dry_run)
+          {
+            log_info ("socketdir is '%s'\n", socketdir);
+            if ((flags &   1)) log_info ("\tgeneral error\n");
+            if ((flags &   2)) log_info ("\tno /run/user dir\n");
+            if ((flags &   4)) log_info ("\tbad permissions\n");
+            if ((flags &   8)) log_info ("\tbad permissions (subdir)\n");
+            if ((flags &  16)) log_info ("\tmkdir failed\n");
+            if ((flags &  32)) log_info ("\tnon-default homedir\n");
+            if ((flags &  64)) log_info ("\tno such subdir\n");
+            if ((flags & 128)) log_info ("\tusing homedir as fallback\n");
+          }
+
+        if ((flags & ~32) && !opt.dry_run)
+          gc_error (1, 0, "error creating socket directory");
+
+        xfree (socketdir);
+      }
+      break;
+
+    case aRemoveSocketDir:
+      {
+        char *socketdir;
+        unsigned int flags;
+
+        /* Check the /var/run dir.  */
+        socketdir = _gnupg_socketdir_internal (1, &flags);
+        if ((flags & 128))
+          log_info ("ignoring request to remove non /run/user socket dir\n");
+        else if (opt.dry_run)
+          ;
+        else if (rmdir (socketdir))
+          gc_error (1, errno, "error removing '%s'", socketdir);
+
+        xfree (socketdir);
+      }
+      break;
+
     }
 
   if (outfp != es_stdout)
index 968dca6..6adc1f5 100644 (file)
@@ -38,6 +38,7 @@
 #include "i18n.h"
 #include "../common/exectool.h"
 #include "../common/sysutils.h"
+#include "../common/ccparray.h"
 #include "gpgtar.h"
 
 #ifndef HAVE_LSTAT
@@ -888,8 +889,8 @@ gpgtar_create (char **inpattern, int encrypt, int sign)
 
   if (encrypt || sign)
     {
-      int i;
       strlist_t arg;
+      ccparray_t ccp;
       const char **argv;
 
       err = es_fseek (outstream, 0, SEEK_SET);
@@ -899,46 +900,39 @@ gpgtar_create (char **inpattern, int encrypt, int sign)
       /* '--encrypt' may be combined with '--symmetric', but 'encrypt'
          is set either way.  Clear it if no recipients are specified.
          XXX: Fix command handling.  */
-       if (opt.symmetric && opt.recipients == NULL)
-         encrypt = 0;
-
-      argv = xtrycalloc (strlist_length (opt.gpg_arguments)
-                         + 2 * strlist_length (opt.recipients)
-                         + 1 + !!encrypt + !!sign + 2 * !!opt.user
-                         + !!opt.symmetric,
-                         sizeof *argv);
-      if (argv == NULL)
-        {
-          err = gpg_error_from_syserror ();
-          goto leave;
-        }
-      i = 0;
+      if (opt.symmetric && opt.recipients == NULL)
+        encrypt = 0;
+
+      ccparray_init (&ccp, 0);
       if (encrypt)
-        argv[i++] = "--encrypt";
+        ccparray_put (&ccp, "--encrypt");
       if (sign)
-        argv[i++] = "--sign";
+        ccparray_put (&ccp, "--sign");
       if (opt.user)
         {
-          argv[i++] = "--local-user";
-          argv[i++] = opt.user;
+          ccparray_put (&ccp, "--local-user");
+          ccparray_put (&ccp, opt.user);
         }
       if (opt.symmetric)
-        argv[i++] = "--symmetric";
+        ccparray_put (&ccp, "--symmetric");
       for (arg = opt.recipients; arg; arg = arg->next)
         {
-          argv[i++] = "--recipient";
-          argv[i++] = arg->d;
+          ccparray_put (&ccp, "--recipient");
+          ccparray_put (&ccp, arg->d);
         }
       for (arg = opt.gpg_arguments; arg; arg = arg->next)
-        argv[i++] = arg->d;
-      argv[i++] = NULL;
-      assert (i == strlist_length (opt.gpg_arguments)
-              + 2 * strlist_length (opt.recipients)
-              + 1 + !!encrypt + !!sign + 2 * !!opt.user
-              + !!opt.symmetric);
+        ccparray_put (&ccp, arg->d);
+
+      ccparray_put (&ccp, NULL);
+      argv = ccparray_get (&ccp, NULL);
+      if (!argv)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
-                                    outstream, cipher_stream);
+                                    outstream, NULL, cipher_stream, NULL, NULL);
       xfree (argv);
       if (err)
         goto leave;
index 95f2b56..866215b 100644 (file)
@@ -30,6 +30,7 @@
 #include "i18n.h"
 #include "../common/exectool.h"
 #include "../common/sysutils.h"
+#include "../common/ccparray.h"
 #include "gpgtar.h"
 
 
@@ -299,8 +300,8 @@ gpgtar_extract (const char *filename, int decrypt)
 
   if (decrypt)
     {
-      int i;
       strlist_t arg;
+      ccparray_t ccp;
       const char **argv;
 
       cipher_stream = stream;
@@ -311,22 +312,22 @@ gpgtar_extract (const char *filename, int decrypt)
           goto leave;
         }
 
-      argv = xtrycalloc (strlist_length (opt.gpg_arguments) + 2,
-                         sizeof *argv);
-      if (argv == NULL)
+      ccparray_init (&ccp, 0);
+
+      ccparray_put (&ccp, "--decrypt");
+      for (arg = opt.gpg_arguments; arg; arg = arg->next)
+        ccparray_put (&ccp, arg->d);
+
+      ccparray_put (&ccp, NULL);
+      argv = ccparray_get (&ccp, NULL);
+      if (!argv)
         {
           err = gpg_error_from_syserror ();
           goto leave;
         }
-      i = 0;
-      argv[i++] = "--decrypt";
-      for (arg = opt.gpg_arguments; arg; arg = arg->next)
-        argv[i++] = arg->d;
-      argv[i++] = NULL;
-      assert (i == strlist_length (opt.gpg_arguments) + 2);
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
-                                    cipher_stream, stream);
+                                    cipher_stream, NULL, stream, NULL, NULL);
       xfree (argv);
       if (err)
         goto leave;
index 25c70d2..1d59d9c 100644 (file)
@@ -27,6 +27,7 @@
 #include "i18n.h"
 #include "gpgtar.h"
 #include "../common/exectool.h"
+#include "../common/ccparray.h"
 
 
 \f
@@ -299,8 +300,8 @@ gpgtar_list (const char *filename, int decrypt)
 
   if (decrypt)
     {
-      int i;
       strlist_t arg;
+      ccparray_t ccp;
       const char **argv;
 
       cipher_stream = stream;
@@ -311,22 +312,22 @@ gpgtar_list (const char *filename, int decrypt)
           goto leave;
         }
 
-      argv = xtrycalloc (strlist_length (opt.gpg_arguments) + 2,
-                         sizeof *argv);
-      if (argv == NULL)
+      ccparray_init (&ccp, 0);
+
+      ccparray_put (&ccp, "--decrypt");
+      for (arg = opt.gpg_arguments; arg; arg = arg->next)
+        ccparray_put (&ccp, arg->d);
+
+      ccparray_put (&ccp, NULL);
+      argv = ccparray_get (&ccp, NULL);
+      if (!argv)
         {
           err = gpg_error_from_syserror ();
           goto leave;
         }
-      i = 0;
-      argv[i++] = "--decrypt";
-      for (arg = opt.gpg_arguments; arg; arg = arg->next)
-        argv[i++] = arg->d;
-      argv[i++] = NULL;
-      assert (i == strlist_length (opt.gpg_arguments) + 2);
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
-                                    cipher_stream, stream);
+                                    cipher_stream, NULL, stream, NULL, NULL);
       xfree (argv);
       if (err)
         goto leave;
index f911bd2..215ab52 100644 (file)
@@ -1117,7 +1117,7 @@ dump_structure (rfc822parse_t msg, part_t part, int indent)
     {
       rfc822parse_field_t ctx;
       part_t save_part; /* ugly hack - we should have a function to
-                           get part inforation. */
+                           get part information. */
       const char *s;
 
       save_part = msg->current_part;
@@ -1177,8 +1177,13 @@ show_event (rfc822parse_event_t event)
     case RFC822PARSE_T2BODY: s= "T2Body"; break;
     case RFC822PARSE_FINISH: s= "Finish"; break;
     case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break;
+    case RFC822PARSE_LEVEL_DOWN: s= "Level_Down"; break;
+    case RFC822PARSE_LEVEL_UP:   s= "Level_Up"; break;
     case RFC822PARSE_BOUNDARY: s= "Boundary"; break;
     case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break;
+    case RFC822PARSE_BEGIN_HEADER: s= "Begin_Header"; break;
+    case RFC822PARSE_PREAMBLE: s= "Preamble"; break;
+    case RFC822PARSE_EPILOGUE: s= "Epilogue"; break;
     default: s= "***invalid event***"; break;
     }
   printf ("*** got RFC822 event %s\n", s);
index 4b90cd2..3732b39 100644 (file)
@@ -214,7 +214,7 @@ my_strusage (int level)
             "Call a simple symmetric encryption tool\n");
       break;
     case 31: p = "\nHome: "; break;
-    case 32: p = opt.homedir; break;
+    case 32: p = gnupg_homedir (); break;
     case 33: p = "\n"; break;
 
     default: p = NULL; break;
@@ -896,8 +896,6 @@ main (int argc, char **argv)
   i18n_init();
   init_common_subsystems (&argc, &argv);
 
-  opt.homedir = default_homedir ();
-
   /* Check whether we have a config file given on the commandline */
   orig_argc = argc;
   orig_argv = argv;
@@ -915,11 +913,11 @@ 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;
+       gnupg_set_homedir (pargs.r.ret_str);
     }
 
   if (default_config)
-    configname = make_filename (opt.homedir, "symcryptrun.conf", NULL );
+    configname = make_filename (gnupg_homedir (), "symcryptrun.conf", NULL );
 
   argc = orig_argc;
   argv = orig_argv;
@@ -1010,7 +1008,7 @@ main (int argc, char **argv)
 
   /* Tell simple-pwquery about the the standard socket name.  */
   {
-    char *tmp = make_filename (opt.homedir, GPG_AGENT_SOCK_NAME, NULL);
+    char *tmp = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
     simple_pw_set_socket (tmp);
     xfree (tmp);
   }