[git] GnuPG - branch, master, updated. gnupg-2.1.15-79-g875ac92

by Neal H. Walfield cvs at cvs.gnupg.org
Tue Sep 6 21:37:54 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  875ac9216f1383851a82bd240cadb17c7112f6a8 (commit)
       via  a9e6db6c7e23d9f4b8de59f5cabbf9eb6a59e626 (commit)
      from  f2249b737055f84842778285bbeff5e61fa55225 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 875ac9216f1383851a82bd240cadb17c7112f6a8
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Sep 6 15:45:38 2016 +0200

    g10: Record and show statistics for encrypted messages when using TOFU
    
    * g10/tofu.c: Include "sqrtu32.h".
    (struct tofu_dbs_s.s): Rename get_trust_gather_other_keys to
    get_trust_gather_signature_stats.  Add new field
    get_trust_gather_encryption_stats.
    (initdb): Create the encryptions table.
    (ask_about_binding): Show the encryption statistics too.
    (tofu_register): Rename from this...
    (tofu_register_signature): ... to this and update callers.
    (tofu_register_encryption): New function.
    (write_stats_status): Add parameters encryption_count,
    encryption_first_done and encryption_most_recent.  Update callers.
    Compute the trust using the euclidean distance of the signature and
    signature count.  Compare with twice the threshold.  Include
    encryption count information in the TFS and TOFU_STATS lines.
    (show_statistics): Also get information about the encrypted messages.
    * g10/trustdb.c (tdb_get_validity_core): Use it.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/doc/DETAILS b/doc/DETAILS
index cf779d2..b5431d0 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -238,8 +238,10 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     - Field 4 :: signcount - The number of signatures seen.
     - Field 5 :: encrcount - The number of encryptions done.
     - Field 6 :: policy - A string with the policy
-    - Field 7 :: first-seen - a timestamp or 0 if not known.
-    - Field 8 :: most-recent-seen - a timestamp or 0 if not known.
+    - Field 7 :: signture-first-seen - a timestamp or 0 if not known.
+    - Field 8 :: signature-most-recent-seen - a timestamp or 0 if not known.
+    - Field 9 :: encryption-first-done - a timestamp or 0 if not known.
+    - Field 10 :: encryption-most-recent-done - a timestamp or 0 if not known.
 
 *** TRU - Trust database information
     Example for a "tru" trust base record:
@@ -715,7 +717,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     userid encoded in UTF-8 and percent escaped.  The fingerprint is
     indentical for all TOFU_USER lines up to a NEWSIG line.
 
-*** TOFU_STATS <validity> <sign-count> 0 [<policy> [<tm1> <tm2>]]
+*** TOFU_STATS <validity> <sign-count> 0 [<policy> [<tm1> <tm2> <tm3> <tm4>]]
 
     Statistics for the current user id.
 
@@ -734,9 +736,11 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     - ask     :: Policy is "ask"
     - unknown :: Policy is not known.
 
-    TM1 ist the time the first messages was verified.  TM2 is the time
-    the most recent message was verified.  Both may either be seconds
-    since Epoch or an ISO time string (yyyymmddThhmmss).
+    TM1 ist the time the first message was verified.  TM2 is the time
+    the most recent message was verified.  TM3 is the time the first
+    message was encrypted.  TM4 is the most recent encryption. All may
+    either be seconds since Epoch or an ISO time string
+    (yyyymmddThhmmss).
 
 *** TOFU_STATS_SHORT <long_string>
 
diff --git a/g10/Makefile.am b/g10/Makefile.am
index fc33e83..7b87e6a 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -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 gpgsql.c gpgsql.h
+tofu_source = tofu.h tofu.c gpgsql.c gpgsql.h sqrtu32.c sqrtu32.h
 else
 tofu_source =
 endif
diff --git a/g10/pkclist.c b/g10/pkclist.c
index f7b2483..62f5b7f 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1314,6 +1314,29 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
       rc = GPG_ERR_NO_USER_ID;
     }
 
+#ifdef USE_TOFU
+  if (! rc && (opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU))
+    {
+      PK_LIST iter;
+      for (iter = pk_list; iter; iter = iter->next)
+        {
+          int rc2;
+
+          /* Note: we already resolved any conflict when looking up
+             the key.  Don't annoy the user again if she selected
+             accept once.  */
+          rc2 = tofu_register_encryption (ctrl, iter->pk, NULL, 0);
+          if (rc2)
+            log_info ("WARNING: Failed to register encryption to %s"
+                      " with TOFU engine\n",
+                      keystr (pk_main_keyid (iter->pk)));
+          else if (DBG_TRUST)
+            log_debug ("Registered encryption to %s with TOFU DB.\n",
+                      keystr (pk_main_keyid (iter->pk)));
+        }
+    }
+#endif /*USE_TOFU*/
+
  fail:
 
   if ( rc )
diff --git a/g10/tofu.c b/g10/tofu.c
index 083f5ef..defc54f 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -41,6 +41,7 @@
 #include "mkdir_p.h"
 #include "gpgsql.h"
 #include "status.h"
+#include "sqrtu32.h"
 
 #include "tofu.h"
 
@@ -76,7 +77,8 @@ struct tofu_dbs_s
     sqlite3_stmt *get_policy_select_policy_and_conflict;
     sqlite3_stmt *get_trust_bindings_with_this_email;
     sqlite3_stmt *get_trust_gather_other_user_ids;
-    sqlite3_stmt *get_trust_gather_other_keys;
+    sqlite3_stmt *get_trust_gather_signature_stats;
+    sqlite3_stmt *get_trust_gather_encryption_stats;
     sqlite3_stmt *register_already_seen;
     sqlite3_stmt *register_insert;
   } s;
@@ -649,6 +651,19 @@ initdb (sqlite3 *db)
     }
 
  out:
+  if (! rc)
+    {
+      /* Early version of the v1 format did not include the encryption
+         table.  Add it.  */
+      sqlite3_exec (db,
+                    "create table if not exists encryptions"
+                    " (binding INTEGER NOT NULL,"
+                    "  time INTEGER);"
+                    "create index if not exists encryptions_binding"
+                    " on encryptions (binding);\n",
+                    NULL, NULL, &err);
+    }
+
   if (rc)
     {
       rc = sqlite3_exec (db, "rollback;", NULL, NULL, &err);
@@ -1384,39 +1399,42 @@ ask_about_binding (ctrl_t ctrl,
   strlist_rev (&conflict_set);
   for (iter = conflict_set; iter && ! rc; iter = iter->next)
     {
+#define STATS_SQL(table, time, sign)                         \
+         "select fingerprint, policy, time_ago, count(*)\n" \
+         " from\n" \
+         "  (select bindings.*,\n" \
+         "     "sign" case\n" \
+         "       when delta ISNULL then 1\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 2\n" \
+         "      when delta < ("STRINGIFY (TIME_AGO_SMALL_THRESHOLD)")\n" \
+         "       then 3\n" \
+         "      when delta < ("STRINGIFY (TIME_AGO_MEDIUM_THRESHOLD)")\n" \
+         "       then 4\n" \
+         "      when delta < ("STRINGIFY (TIME_AGO_LARGE_THRESHOLD)")\n" \
+         "       then 5\n" \
+         "      else 6\n" \
+         "     end time_ago,\n" \
+         "    delta time_ago_raw\n" \
+         "   from bindings\n" \
+         "   left join\n" \
+         "     (select *,\n" \
+         "        cast(strftime('%s','now') - " time " as real) delta\n" \
+         "       from " table ") ss\n" \
+         "    on ss.binding = bindings.oid)\n" \
+         " where email = ? and fingerprint = ?\n" \
+         " group by time_ago\n" \
+         /* Make sure the current key is first.  */ \
+         " order by time_ago desc;\n"
+
       rc = gpgsql_stepx
-        (dbs->db, &dbs->s.get_trust_gather_other_keys,
+        (dbs->db, &dbs->s.get_trust_gather_signature_stats,
          signature_stats_collect_cb, &stats, &sqerr,
-         "select fingerprint, policy, time_ago, count(*)\n"
-         " from\n"
-         "  (select bindings.*,\n"
-         "     case\n"
-         "       when delta ISNULL then 1\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 2\n"
-         "      when delta < ("STRINGIFY (TIME_AGO_SMALL_THRESHOLD)")\n"
-         "       then 3\n"
-         "      when delta < ("STRINGIFY (TIME_AGO_MEDIUM_THRESHOLD)")\n"
-         "       then 4\n"
-         "      when delta < ("STRINGIFY (TIME_AGO_LARGE_THRESHOLD)")\n"
-         "       then 5\n"
-         "      else 6\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 = ? and fingerprint = ?\n"
-         " group by time_ago\n"
-         /* Make sure the current key is first.  */
-         " order by time_ago desc;\n",
+         STATS_SQL ("signatures", "sig_time", ""),
          GPGSQL_ARG_STRING, email,
          GPGSQL_ARG_STRING, iter->d,
          GPGSQL_ARG_END);
@@ -1426,6 +1444,23 @@ ask_about_binding (ctrl_t ctrl,
       if (!stats || strcmp (iter->d, stats->fingerprint) != 0)
         /* No stats for this binding.  Add a dummy entry.  */
         signature_stats_prepend (&stats, iter->d, TOFU_POLICY_AUTO, 1, 1);
+
+      rc = gpgsql_stepx
+        (dbs->db, &dbs->s.get_trust_gather_encryption_stats,
+         signature_stats_collect_cb, &stats, &sqerr,
+         STATS_SQL ("encryptions", "time", "-"),
+         GPGSQL_ARG_STRING, email,
+         GPGSQL_ARG_STRING, iter->d,
+         GPGSQL_ARG_END);
+      if (rc)
+        break;
+
+#undef STATS_SQL
+
+      if (!stats || strcmp (iter->d, stats->fingerprint) != 0
+          || stats->time_ago > 0)
+        /* No stats for this binding.  Add a dummy entry.  */
+        signature_stats_prepend (&stats, iter->d, TOFU_POLICY_AUTO, -1, 1);
     }
   end_transaction (ctrl, 0);
   strlist_rev (&conflict_set);
@@ -1459,6 +1494,13 @@ ask_about_binding (ctrl_t ctrl,
                   email);
       for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
         {
+#if 0
+          log_debug ("%s: time_ago: %ld; count: %ld\n",
+                     stats_iter->fingerprint,
+                     stats_iter->time_ago,
+                     stats_iter->count);
+#endif
+
           if (! key || strcmp (key, stats_iter->fingerprint))
             {
               int this_key;
@@ -1499,7 +1541,7 @@ ask_about_binding (ctrl_t ctrl,
               seen_in_past = 0;
             }
 
-          if (stats_iter->time_ago == 1)
+          if (abs(stats_iter->time_ago) == 1)
             {
               /* The 1 in this case is the NULL entry.  */
               log_assert (stats_iter->count == 1);
@@ -1510,12 +1552,18 @@ ask_about_binding (ctrl_t ctrl,
           es_fputs ("    ", fp);
           /* TANSLATORS: This string is concatenated with one of
            * the day/week/month strings to form one sentence.  */
-          es_fprintf (fp, ngettext("Verified %d message",
-                                   "Verified %d messages",
-                                   seen_in_past), seen_in_past);
+          if (stats_iter->time_ago > 0)
+            es_fprintf (fp, ngettext("Verified %d message",
+                                     "Verified %d messages",
+                                     seen_in_past), seen_in_past);
+          else
+            es_fprintf (fp, ngettext("Encrypted %d message",
+                                     "Encrypted %d messages",
+                                     seen_in_past), seen_in_past);
+
           if (!stats_iter->count)
             es_fputs (".", fp);
-          else if (stats_iter->time_ago == 2)
+          else if (abs(stats_iter->time_ago) == 2)
             {
               es_fprintf (fp, "in the future.");
               /* Reset it.  */
@@ -1523,25 +1571,25 @@ ask_about_binding (ctrl_t ctrl,
             }
           else
             {
-              if (stats_iter->time_ago == 3)
+              if (abs(stats_iter->time_ago) == 3)
                 es_fprintf (fp, ngettext(" over the past days.",
                                          " over the past %d days.",
                                          seen_in_past),
                             TIME_AGO_SMALL_THRESHOLD
                             / TIME_AGO_UNIT_SMALL);
-              else if (stats_iter->time_ago == 4)
+              else if (abs(stats_iter->time_ago) == 4)
                 es_fprintf (fp, ngettext(" over the past month.",
                                          " over the past %d months.",
                                          seen_in_past),
                             TIME_AGO_MEDIUM_THRESHOLD
                             / TIME_AGO_UNIT_MEDIUM);
-              else if (stats_iter->time_ago == 5)
+              else if (abs(stats_iter->time_ago) == 5)
                 es_fprintf (fp, ngettext(" over the past year.",
                                          " over the past %d years.",
                                          seen_in_past),
                             TIME_AGO_LARGE_THRESHOLD
                             / TIME_AGO_UNIT_LARGE);
-              else if (stats_iter->time_ago == 6)
+              else if (abs(stats_iter->time_ago) == 6)
                 es_fprintf (fp, _(" in the past."));
               else
                 log_assert (! "Broken SQL.\n");
@@ -2349,46 +2397,59 @@ time_ago_str (long long int t)
 /* If FP is NULL, write TOFU_STATS status line.  If FP is not NULL
  * write a "tfs" record to that stream. */
 static void
-write_stats_status (estream_t fp, long messages, enum tofu_policy policy,
-                    unsigned long first_seen,
-                    unsigned long most_recent_seen)
+write_stats_status (estream_t fp,
+                    enum tofu_policy policy,
+                    unsigned long signature_count,
+                    unsigned long signature_first_seen,
+                    unsigned long signature_most_recent,
+                    unsigned long encryption_count,
+                    unsigned long encryption_first_done,
+                    unsigned long encryption_most_recent)
 {
   const char *validity;
 
+  /* Use the euclidean distance rather then the sum of the magnitudes
+     to ensure a balance between verified signatures and encrypted
+     messages.  */
+  float messages = sqrtu32 (signature_count) + sqrtu32 (encryption_count);
+
   if (messages < 1)
     validity = "1"; /* Key without history.  */
-  else if (messages < BASIC_TRUST_THRESHOLD)
+  else if (messages < sqrtu32 (2 * BASIC_TRUST_THRESHOLD))
     validity = "2"; /* Key with too little history.  */
-  else if (messages < FULL_TRUST_THRESHOLD)
+  else if (messages < sqrtu32 (2 * FULL_TRUST_THRESHOLD))
     validity = "3"; /* Key with enough history for basic trust.  */
   else
     validity = "4"; /* Key with a lot of history.  */
 
   if (fp)
     {
-      es_fprintf (fp, "tfs:1:%s:%ld:0:%s:%lu:%lu:\n",
-                  validity, messages,
+      es_fprintf (fp, "tfs:1:%s:%ld:%ld:%s:%lu:%lu:%lu:%lu:\n",
+                  validity, signature_count, encryption_count,
                   tofu_policy_str (policy),
-                  first_seen, most_recent_seen);
+                  signature_first_seen, signature_most_recent,
+                  encryption_first_done, encryption_most_recent);
     }
   else
     {
       char numbuf1[35];
       char numbuf2[35];
       char numbuf3[35];
+      char numbuf4[35];
+      char numbuf5[35];
+      char numbuf6[35];
 
-      snprintf (numbuf1, sizeof numbuf1, " %ld", messages);
-      *numbuf2 = *numbuf3 = 0;
-      if (first_seen && most_recent_seen)
-        {
-          snprintf (numbuf2, sizeof numbuf2, " %lu", first_seen);
-          snprintf (numbuf3, sizeof numbuf3, " %lu", most_recent_seen);
-        }
+      snprintf (numbuf1, sizeof numbuf1, " %ld", signature_count);
+      snprintf (numbuf2, sizeof numbuf2, " %ld", encryption_count);
+      snprintf (numbuf3, sizeof numbuf3, " %lu", signature_first_seen);
+      snprintf (numbuf4, sizeof numbuf4, " %lu", signature_most_recent);
+      snprintf (numbuf5, sizeof numbuf5, " %lu", encryption_first_done);
+      snprintf (numbuf6, sizeof numbuf6, " %lu", encryption_most_recent);
 
       write_status_strings (STATUS_TOFU_STATS,
-                            validity, numbuf1, " 0",
+                            validity, numbuf1, numbuf2,
                             " ", tofu_policy_str (policy),
-                            numbuf2, numbuf3,
+                            numbuf3, numbuf4, numbuf5, numbuf6,
                             NULL);
     }
 }
@@ -2401,13 +2462,24 @@ show_statistics (tofu_dbs_t dbs, const char *fingerprint,
 		 const char *email, const char *user_id,
 		 estream_t outfp)
 {
+  unsigned long now = gnupg_get_time ();
+  enum tofu_policy policy = get_policy (dbs, fingerprint, email, NULL);
+
   char *fingerprint_pp;
   int rc;
   strlist_t strlist = NULL;
   char *err = NULL;
 
+  unsigned long signature_first_seen = 0;
+  unsigned long signature_most_recent = 0;
+  unsigned long signature_count = 0;
+  unsigned long encryption_first_done = 0;
+  unsigned long encryption_most_recent = 0;
+  unsigned long encryption_count = 0;
+
   fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
 
+  /* Get the signature stats.  */
   rc = gpgsql_exec_printf
     (dbs->db, strings_collect_cb, &strlist, &err,
      "select count (*), min (signatures.time), max (signatures.time)\n"
@@ -2423,191 +2495,217 @@ show_statistics (tofu_dbs_t dbs, const char *fingerprint,
       goto out;
     }
 
-  if (!outfp)
-    write_status_text_and_buffer (STATUS_TOFU_USER, fingerprint,
-                                  email, strlen (email), 0);
+  if (strlist)
+    {
+      log_assert (strlist->next);
+      log_assert (strlist->next->next);
+      log_assert (! strlist->next->next->next);
+
+      string_to_long (&signature_count, strlist->d, -1, __LINE__);
+      string_to_long (&signature_first_seen, strlist->next->d, -1, __LINE__);
+      string_to_long (&signature_most_recent,
+                      strlist->next->next->d, -1, __LINE__);
+
+      free_strlist (strlist);
+      strlist = NULL;
+    }
 
-  if (! strlist)
+  /* Get the encryption stats.  */
+  rc = gpgsql_exec_printf
+    (dbs->db, strings_collect_cb, &strlist, &err,
+     "select count (*), min (encryptions.time), max (encryptions.time)\n"
+     " from encryptions\n"
+     " left join bindings on encryptions.binding = bindings.oid\n"
+     " where fingerprint = %Q and email = %Q;",
+     fingerprint, email);
+  if (rc)
     {
-      if (!outfp)
-        log_info (_("Have never verified a message signed by key %s!\n"),
-                  fingerprint_pp);
-      write_stats_status (outfp, 0, TOFU_POLICY_NONE, 0, 0);
+      log_error (_("error reading TOFU database: %s\n"), err);
+      print_further_info ("getting statistics");
+      sqlite3_free (err);
+      goto out;
     }
-  else
+
+  if (strlist)
     {
-      unsigned long now = gnupg_get_time ();
-      signed long messages;
-      unsigned long first_seen;
-      unsigned long most_recent_seen;
+      log_assert (strlist->next);
+      log_assert (strlist->next->next);
+      log_assert (! strlist->next->next->next);
+
+      string_to_long (&encryption_count, strlist->d, -1, __LINE__);
+      string_to_long (&encryption_first_done, strlist->next->d, -1, __LINE__);
+      string_to_long (&encryption_most_recent,
+                      strlist->next->next->d, -1, __LINE__);
+
+      free_strlist (strlist);
+      strlist = NULL;
+    }
 
-      log_assert (strlist_length (strlist) == 3);
+  if (!outfp)
+    write_status_text_and_buffer (STATUS_TOFU_USER, fingerprint,
+                                  email, strlen (email), 0);
 
-      string_to_long (&messages, strlist->d, -1, __LINE__);
+  write_stats_status (outfp, policy,
+                      signature_count,
+                      signature_first_seen,
+                      signature_most_recent,
+                      encryption_count,
+                      encryption_first_done,
+                      encryption_most_recent);
 
-      if (messages == 0 && *strlist->next->d == '\0')
-        { /* min(NULL) => NULL => "".  */
-          first_seen = 0;
-          most_recent_seen = 0;
+  if (!outfp)
+    {
+      estream_t fp;
+      char *msg;
+
+      fp = es_fopenmem (0, "rw,samethread");
+      if (! fp)
+        log_fatal ("error creating memory stream: %s\n",
+                   gpg_strerror (gpg_error_from_syserror()));
+
+      if (signature_count == 0)
+        {
+          es_fprintf (fp, _("Verified %ld messages signed by \"%s\"."),
+                      0L, user_id);
+          es_fputc ('\n', fp);
         }
       else
-	{
-          string_to_ulong (&first_seen, strlist->next->d, -1, __LINE__);
-          if (first_seen > now)
-            {
-              log_debug ("time-warp - tofu DB has a future value (%lu, %lu)\n",
-                         first_seen, now);
-              first_seen = now;
-            }
-	  string_to_ulong (&most_recent_seen, strlist->next->next->d, -1,
-                           __LINE__);
-          if (most_recent_seen > now)
+        {
+          char *first_seen_ago_str = time_ago_str (now - signature_first_seen);
+
+          /* TRANSLATORS: The final %s is replaced by a string like
+             "7 months, 1 day, 5 minutes, 0 seconds". */
+          es_fprintf (fp,
+                      ngettext("Verified %ld message signed by \"%s\"\n"
+                               "in the past %s.",
+                               "Verified %ld messages signed by \"%s\"\n"
+                               "in the past %s.",
+                               signature_count),
+                      signature_count, user_id, first_seen_ago_str);
+
+          if (signature_count > 1)
             {
-              log_debug ("time-warp - tofu DB has a future value (%lu, %lu)\n",
-                         most_recent_seen, now);
-              most_recent_seen = now;
+              char *tmpstr = time_ago_str (now - signature_most_recent);
+              es_fputs ("  ", fp);
+              es_fprintf (fp, _("The most recent message was"
+                                " verified %s ago."), tmpstr);
+              xfree (tmpstr);
             }
+          xfree (first_seen_ago_str);
+        }
 
-	}
+      es_fprintf (fp, "  ");
 
-      if (messages == -1 || first_seen == -1)
+      if (encryption_count == 0)
         {
-          write_stats_status (outfp, 0, TOFU_POLICY_NONE, 0, 0);
-          if (!outfp)
-            log_info (_("Failed to collect signature statistics for \"%s\"\n"
-                        "(key %s)\n"),
-                      user_id, fingerprint_pp);
-        }
-      else if (outfp)
-        {
-          write_stats_status (outfp, messages,
-                              get_policy (dbs, fingerprint, email, NULL),
-                              first_seen, most_recent_seen);
+          es_fprintf (fp, _("Encrypted %ld messages to \"%s\"."),
+                      0L, user_id);
+          es_fputc ('\n', fp);
         }
       else
-	{
-	  enum tofu_policy policy = get_policy (dbs, fingerprint, email, NULL);
-	  estream_t fp;
-	  char *msg;
-
-          write_stats_status (NULL, messages,
-                              policy,
-                              first_seen, most_recent_seen);
-
-	  fp = es_fopenmem (0, "rw,samethread");
-	  if (! fp)
-            log_fatal ("error creating memory stream: %s\n",
-                       gpg_strerror (gpg_error_from_syserror()));
-
-	  if (messages == 0)
+        {
+          char *first_done_ago_str = time_ago_str (now - encryption_first_done);
+
+          /* TRANSLATORS: The final %s is replaced by a string like
+             "7 months, 1 day, 5 minutes, 0 seconds". */
+          es_fprintf (fp,
+                      ngettext("Encrypted %ld message to \"%s\"\n"
+                               "in the past %s.",
+                               "Encrypted %ld messages to \"%s\"\n"
+                               "in the past %s.",
+                               encryption_count),
+                      encryption_count, user_id, first_done_ago_str);
+
+          if (encryption_count > 1)
             {
-              es_fprintf (fp, _("Verified %ld messages signed by \"%s\"."),
-                          0L, user_id);
-              es_fputc ('\n', fp);
+              char *tmpstr = time_ago_str (now - encryption_most_recent);
+              es_fputs ("  ", fp);
+              es_fprintf (fp, _("The most recent message was"
+                                " verified %s ago."), tmpstr);
+              xfree (tmpstr);
             }
-	  else
-	    {
-              char *first_seen_ago_str = time_ago_str (now - first_seen);
-
-              /* TRANSLATORS: The final %s is replaced by a string like
-                 "7 months, 1 day, 5 minutes, 0 seconds". */
-	      es_fprintf (fp,
-                          ngettext("Verified %ld message signed by \"%s\"\n"
-                                   "in the past %s.",
-                                   "Verified %ld messages signed by \"%s\"\n"
-                                   "in the past %s.",
-                                   messages),
-			  messages, user_id, first_seen_ago_str);
-
-              if (messages > 1)
-                {
-                  char *tmpstr = time_ago_str (now - most_recent_seen);
-                  es_fputs ("  ", fp);
-                  es_fprintf (fp, _("The most recent message was"
-                                    " verified %s ago."), tmpstr);
-                  xfree (tmpstr);
-                }
-              xfree (first_seen_ago_str);
+          xfree (first_done_ago_str);
+        }
 
-              if (opt.verbose)
-                {
-                  es_fputs ("  ", fp);
-                  es_fputc ('(', fp);
-                  es_fprintf (fp, _("policy: %s"), tofu_policy_str (policy));
-                  es_fputs (")\n", fp);
-                }
-              else
-                es_fputs ("\n", fp);
-            }
+      if (opt.verbose)
+        {
+          es_fputs ("  ", fp);
+          es_fputc ('(', fp);
+          es_fprintf (fp, _("policy: %s"), tofu_policy_str (policy));
+          es_fputs (")\n", fp);
+        }
+      else
+        es_fputs ("\n", fp);
 
-          {
-            char *tmpmsg, *p;
-            es_fputc (0, fp);
-            if (es_fclose_snatch (fp, (void **) &tmpmsg, NULL))
-              log_fatal ("error snatching memory stream\n");
-            msg = format_text (tmpmsg, 0, 72, 80);
-            es_free (tmpmsg);
-
-            /* 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 = ' ';
 
-          }
+      {
+        char *tmpmsg, *p;
+        es_fputc (0, fp);
+        if (es_fclose_snatch (fp, (void **) &tmpmsg, NULL))
+          log_fatal ("error snatching memory stream\n");
+        msg = format_text (tmpmsg, 0, 72, 80);
+        es_free (tmpmsg);
+
+        /* 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);
-          xfree (msg);
-
-	  if (policy == TOFU_POLICY_AUTO && messages < BASIC_TRUST_THRESHOLD)
-	    {
-	      char *set_policy_command;
-	      char *text;
-              char *tmpmsg;
-
-	      if (messages == 0)
-		log_info (_("Warning: we have yet to see"
-                            " a message signed by this key and user id!\n"));
-	      else if (messages == 1)
-		log_info (_("Warning: we've only seen a single message"
-                            " signed by this key and user id!\n"));
-
-	      set_policy_command =
-		xasprintf ("gpg --tofu-policy bad %s", fingerprint);
-
-              tmpmsg = xasprintf
-                (ngettext
-                 ("Warning: if you think you've seen more than %ld message "
-                  "signed by this key and user id, then this key might be a "
-                  "forgery!  Carefully examine the email address for small "
-                  "variations.  If the key is suspect, then use\n"
-                  "  %s\n"
-                  "to mark it as being bad.\n",
-                  "Warning: if you think you've seen more than %ld messages "
-                  "signed by this key, then this key might be a forgery!  "
-                      "Carefully examine the email address for small "
-                  "variations.  If the key is suspect, then use\n"
-                  "  %s\n"
-                  "to mark it as being bad.\n",
-                  messages),
-                  messages, set_policy_command);
-              text = format_text (tmpmsg, 0, 72, 80);
-              xfree (tmpmsg);
-	      log_string (GPGRT_LOG_INFO, text);
-              xfree (text);
-
-	      es_free (set_policy_command);
-	    }
-	}
+      log_string (GPGRT_LOG_INFO, msg);
+      xfree (msg);
+
+      if (policy == TOFU_POLICY_AUTO
+          /* Cf. write_stats_status  */
+          && (sqrtu32 (encryption_count) + sqrtu32 (signature_count)
+              < sqrtu32 (2 * BASIC_TRUST_THRESHOLD)))
+        {
+          char *set_policy_command;
+          char *text;
+          char *tmpmsg;
+
+          if (signature_count == 0)
+            log_info (_("Warning: we have yet to see"
+                        " a message signed by this key and user id!\n"));
+          else if (signature_count == 1)
+            log_info (_("Warning: we've only seen a single message"
+                        " signed by this key and user id!\n"));
+
+          set_policy_command =
+            xasprintf ("gpg --tofu-policy bad %s", fingerprint);
+
+          tmpmsg = xasprintf
+            (ngettext
+             ("Warning: if you think you've seen more than %ld message "
+              "signed by this key and user id, then this key might be a "
+              "forgery!  Carefully examine the email address for small "
+              "variations.  If the key is suspect, then use\n"
+              "  %s\n"
+              "to mark it as being bad.\n",
+              "Warning: if you think you've seen more than %ld messages "
+              "signed by this key, then this key might be a forgery!  "
+              "Carefully examine the email address for small "
+              "variations.  If the key is suspect, then use\n"
+              "  %s\n"
+              "to mark it as being bad.\n",
+              signature_count),
+             signature_count, set_policy_command);
+          text = format_text (tmpmsg, 0, 72, 80);
+          xfree (tmpmsg);
+          log_string (GPGRT_LOG_INFO, text);
+          xfree (text);
+
+          es_free (set_policy_command);
+        }
     }
 
  out:
-  free_strlist (strlist);
   xfree (fingerprint_pp);
 
   return;
@@ -2652,9 +2750,10 @@ email_from_user_id (const char *user_id)
    This function returns 0 on success and an error code if an error
    occured.  */
 gpg_error_t
-tofu_register (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
-	       const byte *sig_digest_bin, int sig_digest_bin_len,
-	       time_t sig_time, const char *origin)
+tofu_register_signature (ctrl_t ctrl,
+                         PKT_public_key *pk, strlist_t user_id_list,
+                         const byte *sig_digest_bin, int sig_digest_bin_len,
+                         time_t sig_time, const char *origin)
 {
   gpg_error_t rc;
   tofu_dbs_t dbs;
@@ -2797,6 +2896,114 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
   return rc;
 }
 
+gpg_error_t
+tofu_register_encryption (ctrl_t ctrl,
+                          PKT_public_key *pk, strlist_t user_id_list,
+                          int may_ask)
+{
+  gpg_error_t rc = 0;
+  tofu_dbs_t dbs;
+  kbnode_t kb = NULL;
+  int free_user_id_list = 0;
+  char *fingerprint = NULL;
+  strlist_t user_id;
+  char *err = NULL;
+
+  dbs = opendbs (ctrl);
+  if (! dbs)
+    {
+      rc = gpg_error (GPG_ERR_GENERAL);
+      log_error (_("error opening TOFU database: %s\n"),
+                 gpg_strerror (rc));
+      return rc;
+    }
+
+  /* Make sure PK is a primary key.  */
+  if (keyid_cmp (pk_keyid (pk), pk->main_keyid) != 0
+      || user_id_list)
+    kb = get_pubkeyblock (pk->keyid);
+
+  if (keyid_cmp (pk_keyid (pk), pk->main_keyid) != 0)
+    pk = kb->pkt->pkt.public_key;
+
+  if (! user_id_list)
+    {
+      /* Use all non-revoked user ids.  Do use expired user ids.  */
+      kbnode_t n = kb;
+
+      while ((n = find_next_kbnode (n, PKT_USER_ID)))
+        {
+	  PKT_user_id *uid = n->pkt->pkt.user_id;
+
+          if (uid->is_revoked)
+            continue;
+
+          add_to_strlist (&user_id_list, uid->name);
+        }
+
+      free_user_id_list = 1;
+
+      if (! user_id_list)
+        log_info ("WARNING: Encrypting to %s, which has no"
+                  "non-revoked user ids.\n",
+                  keystr (pk->keyid));
+    }
+
+  fingerprint = hexfingerprint (pk, NULL, 0);
+
+  tofu_begin_batch_update (ctrl);
+  tofu_resume_batch_transaction (ctrl);
+
+  for (user_id = user_id_list; user_id; user_id = user_id->next)
+    {
+      char *email = email_from_user_id (user_id->d);
+
+      /* Make sure the binding exists and that we recognize any
+         conflicts.  */
+      int tl = get_trust (ctrl, pk, fingerprint, email, user_id->d,
+                          may_ask);
+      if (tl == _tofu_GET_TRUST_ERROR)
+        {
+          /* An error.  */
+          xfree (email);
+          goto die;
+        }
+
+      rc = gpgsql_stepx
+        (dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
+         "insert into encryptions\n"
+         " (binding, time)\n"
+         " values\n"
+         " ((select oid from bindings\n"
+         "    where fingerprint = ? and email = ?),\n"
+         "  strftime('%s', 'now'));",
+         GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_STRING, email,
+         GPGSQL_ARG_END);
+      if (rc)
+        {
+          log_error (_("error updating TOFU database: %s\n"), err);
+          print_further_info ("insert encryption");
+          sqlite3_free (err);
+        }
+
+      xfree (email);
+    }
+
+ die:
+  tofu_end_batch_update (ctrl);
+
+  if (kb)
+    release_kbnode (kb);
+
+  if (free_user_id_list)
+    free_strlist (user_id_list);
+
+  xfree (fingerprint);
+
+  return rc;
+}
+
+
 /* Combine a trust level returned from the TOFU trust model with a
    trust level returned by the PGP trust model.  This is primarily of
    interest when the trust model is tofu+pgp (TM_TOFU_PGP).
diff --git a/g10/tofu.h b/g10/tofu.h
index b9826c9..df69a7a 100644
--- a/g10/tofu.h
+++ b/g10/tofu.h
@@ -78,13 +78,24 @@ int tofu_policy_to_trust_level (enum tofu_policy policy);
    data came from, e.g., "email:claws" (default: "unknown").  Note:
    this function does not interact with the user, If there is a
    conflict, or if the binding's policy is ask, the actual interaction
-   is deferred until tofu_get_validity is called..  Set the string
+   is deferred until tofu_get_validity is called.  Set the string
    list FLAG to indicate that a specified user id is expired.  This
    function returns 0 on success and an error code on failure.  */
-gpg_error_t tofu_register (ctrl_t ctrl, PKT_public_key *pk,
-                           strlist_t user_id_list,
-                           const byte *sigs_digest, int sigs_digest_len,
-                           time_t sig_time, const char *origin);
+gpg_error_t tofu_register_signature (ctrl_t ctrl, PKT_public_key *pk,
+                                     strlist_t user_id_list,
+                                     const byte *sigs_digest,
+                                     int sigs_digest_len,
+                                     time_t sig_time, const char *origin);
+
+/* Note that an encrypted mail was sent to <PK, USER_ID>, for each
+   USER_ID in USER_ID_LIST.  (If USER_ID_LIST is NULL, then all
+   non-revoked user ids associated with PK are used.)  If MAY_ASK is
+   set, then may interact with the user to resolve a TOFU
+   conflict.  */
+gpg_error_t tofu_register_encryption (ctrl_t ctrl,
+                                      PKT_public_key *pk,
+                                      strlist_t user_id_list,
+                                      int may_ask);
 
 /* Combine a trust level returned from the TOFU trust model with a
    trust level returned by the PGP trust model.  This is primarily of
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 6f63c34..5457ea1 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -1090,9 +1090,9 @@ tdb_get_validity_core (ctrl_t ctrl,
          into account.  */
       if (sig)
         {
-          err = tofu_register (ctrl, main_pk, user_id_list,
-                               sig->digest, sig->digest_len,
-                               sig->timestamp, "unknown");
+          err = tofu_register_signature (ctrl, main_pk, user_id_list,
+                                         sig->digest, sig->digest_len,
+                                         sig->timestamp, "unknown");
           if (err)
             {
               log_error ("TOFU: error registering signature: %s\n",

commit a9e6db6c7e23d9f4b8de59f5cabbf9eb6a59e626
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Sep 6 14:49:14 2016 +0200

    g10: Simplify the binding statistics shown for a TOFU conflict.
    
    * g10/tofu.c (ask_about_binding): Simplify binding statistics.
    
    --
    Signed-off-by: Neal H. Walfield <neal at g10code.com>

diff --git a/g10/tofu.c b/g10/tofu.c
index d4f6876..083f5ef 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -95,19 +95,15 @@ struct tofu_dbs_s
 /* If a message is signed a couple of hours in the future, just assume
    some clock skew.  */
 #define TIME_AGO_FUTURE_IGNORE (2 * 60 * 60)
-#if 0
-#  define TIME_AGO_UNIT_SMALL 60
-#  define TIME_AGO_MEDIUM_THRESHOLD (60 * TIME_AGO_UNIT_SMALL)
-#  define TIME_AGO_UNIT_MEDIUM (60 * 60)
-#  define TIME_AGO_LARGE_THRESHOLD (24 * 60 * TIME_AGO_UNIT_SMALL)
-#  define TIME_AGO_UNIT_LARGE (24 * 60 * 60)
-#else
-#  define TIME_AGO_UNIT_SMALL (24 * 60 * 60)
-#  define TIME_AGO_MEDIUM_THRESHOLD (4 * TIME_AGO_UNIT_SMALL)
-#  define TIME_AGO_UNIT_MEDIUM (7 * 24 * 60 * 60)
-#  define TIME_AGO_LARGE_THRESHOLD (28 * TIME_AGO_UNIT_SMALL)
-#  define TIME_AGO_UNIT_LARGE (30 * 24 * 60 * 60)
-#endif
+/* Days.  */
+#define TIME_AGO_UNIT_SMALL (24 * 60 * 60)
+#define TIME_AGO_SMALL_THRESHOLD (7 * TIME_AGO_UNIT_SMALL)
+/* Months.  */
+#define TIME_AGO_UNIT_MEDIUM (30 * 24 * 60 * 60)
+#define TIME_AGO_MEDIUM_THRESHOLD (2 * TIME_AGO_UNIT_MEDIUM)
+/* Years.  */
+#define TIME_AGO_UNIT_LARGE (365 * 24 * 60 * 60)
+#define TIME_AGO_LARGE_THRESHOLD (2 * TIME_AGO_UNIT_LARGE)
 
 /* Local prototypes.  */
 static gpg_error_t end_transaction (ctrl_t ctrl, int only_batch);
@@ -1151,14 +1147,10 @@ format_conflict_msg_part1 (int policy, strlist_t conflict_set,
 {
   estream_t fp;
   char *fingerprint;
-  char *binding;
-  int binding_shown = 0;
   char *tmpstr, *text;
 
   log_assert (conflict_set);
-
   fingerprint = conflict_set->d;
-  binding = xasprintf ("<%s, %s>", fingerprint, email);
 
   fp = es_fopenmem (0, "rw,samethread");
   if (!fp)
@@ -1167,38 +1159,31 @@ format_conflict_msg_part1 (int policy, strlist_t conflict_set,
 
   if (policy == TOFU_POLICY_NONE)
     {
-      es_fprintf (fp, _("The binding %s is NOT known."), binding);
+      es_fprintf (fp,
+                  _("This is the first time the email address \"%s\" is "
+                    "being used with key %s."),
+                  email, fingerprint);
       es_fputs ("  ", fp);
-      binding_shown = 1;
     }
   else if (policy == TOFU_POLICY_ASK && conflict_set->next)
     {
-      int conflicts = strlist_length (conflict_set) - 1;
-      es_fprintf (fp,
-                  ngettext("The binding <key: %s, user id: %s> raised a "
-                           "conflict with %d other binding.",
-                           "The binding <key: %s, user id: %s> raised a "
-                           "conflict with %d other bindings.", conflicts),
-                  fingerprint, email, conflicts);
-      es_fprintf (fp,
-                  _("  Since this binding's policy was 'auto', it has been "
-                    "changed to 'ask'."));
+      int conflicts = strlist_length (conflict_set);
+      es_fprintf (fp, _("The email address \"%s\" is associated with %d keys!"),
+                  email, conflicts);
+      if (opt.verbose)
+        es_fprintf (fp,
+                    _("  Since this binding's policy was 'auto', it has been "
+                      "changed to 'ask'."));
       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 ? "" : " ");
+              _("Please indicate whether this email address should"
+                " be associated with key %s or whether you think someone"
+                " is impersonating \"%s\"."),
+              fingerprint, email);
   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");
@@ -1368,7 +1353,7 @@ ask_about_binding (ctrl_t ctrl,
     {
       strlist_t strlist_iter;
 
-      es_fprintf (fp, _("Known user IDs associated with this key:\n"));
+      es_fprintf (fp, _("This key's user IDs:\n"));
       for (strlist_iter = other_user_ids;
            strlist_iter;
            strlist_iter = strlist_iter->next)
@@ -1406,21 +1391,20 @@ ask_about_binding (ctrl_t ctrl,
          " from\n"
          "  (select bindings.*,\n"
          "     case\n"
+         "       when delta ISNULL then 1\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_FUTURE_IGNORE)") then 2\n"
+         "      when delta < ("STRINGIFY (TIME_AGO_SMALL_THRESHOLD)")\n"
+         "       then 3\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"
+         "       then 4\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"
+         "       then 5\n"
+         "      else 6\n"
          "     end time_ago,\n"
          "    delta time_ago_raw\n"
          "   from bindings\n"
@@ -1441,7 +1425,7 @@ ask_about_binding (ctrl_t ctrl,
 
       if (!stats || strcmp (iter->d, stats->fingerprint) != 0)
         /* No stats for this binding.  Add a dummy entry.  */
-        signature_stats_prepend (&stats, iter->d, TOFU_POLICY_AUTO, 0, 0);
+        signature_stats_prepend (&stats, iter->d, TOFU_POLICY_AUTO, 1, 1);
     }
   end_transaction (ctrl, 0);
   strlist_rev (&conflict_set);
@@ -1468,6 +1452,7 @@ ask_about_binding (ctrl_t ctrl,
     {
       char *key = NULL;
       strlist_t binding;
+      int seen_in_past = 0;
 
       es_fprintf (fp, _("Statistics for keys"
                         " with the email address \"%s\":\n"),
@@ -1510,36 +1495,56 @@ ask_about_binding (ctrl_t ctrl,
                             tofu_policy_str (stats_iter->policy));
               es_fputs ("):\n", fp);
               xfree (key_pp);
+
+              seen_in_past = 0;
             }
 
+          if (stats_iter->time_ago == 1)
+            {
+              /* The 1 in this case is the NULL entry.  */
+              log_assert (stats_iter->count == 1);
+              stats_iter->count = 0;
+            }
+          seen_in_past += stats_iter->count;
+
           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);
+          /* TANSLATORS: This string is concatenated with one of
+           * the day/week/month strings to form one sentence.  */
+          es_fprintf (fp, ngettext("Verified %d message",
+                                   "Verified %d messages",
+                                   seen_in_past), seen_in_past);
+          if (!stats_iter->count)
+            es_fputs (".", fp);
+          else if (stats_iter->time_ago == 2)
+            {
+              es_fprintf (fp, "in the future.");
+              /* Reset it.  */
+              seen_in_past = 0;
+            }
           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);
+              if (stats_iter->time_ago == 3)
+                es_fprintf (fp, ngettext(" over the past days.",
+                                         " over the past %d days.",
+                                         seen_in_past),
+                            TIME_AGO_SMALL_THRESHOLD
+                            / TIME_AGO_UNIT_SMALL);
+              else if (stats_iter->time_ago == 4)
+                es_fprintf (fp, ngettext(" over the past month.",
+                                         " over the past %d months.",
+                                         seen_in_past),
+                            TIME_AGO_MEDIUM_THRESHOLD
+                            / TIME_AGO_UNIT_MEDIUM);
+              else if (stats_iter->time_ago == 5)
+                es_fprintf (fp, ngettext(" over the past year.",
+                                         " over the past %d years.",
+                                         seen_in_past),
+                            TIME_AGO_LARGE_THRESHOLD
+                            / TIME_AGO_UNIT_LARGE);
+              else if (stats_iter->time_ago == 6)
+                es_fprintf (fp, _(" in the past."));
               else
-                es_fprintf (fp, ngettext(" over the past %ld month.",
-                                         " over the past %ld months.",
-                                         t_scaled), t_scaled);
+                log_assert (! "Broken SQL.\n");
             }
           es_fputs ("\n", fp);
         }
@@ -1558,11 +1563,11 @@ ask_about_binding (ctrl_t ctrl,
         {
           /* 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 "
+            "Normally, an email address is associated with a single key.  "
+            "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 "
+            "attack!  Before accepting this association, you should talk to or "
             "call the person to make sure this new key is legitimate.";
         }
       textbuf = format_text (text, 0, 72, 80);

-----------------------------------------------------------------------

Summary of changes:
 doc/DETAILS     |  16 +-
 g10/Makefile.am |   2 +-
 g10/pkclist.c   |  23 ++
 g10/tofu.c      | 774 ++++++++++++++++++++++++++++++++++++--------------------
 g10/tofu.h      |  21 +-
 g10/trustdb.c   |   6 +-
 6 files changed, 546 insertions(+), 296 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list