* keyserver.c (keyserver_spawn): Don't mess about with the $PATH.
[gnupg.git] / g10 / trustdb.c
index cb5be10..d69b872 100644 (file)
@@ -1,5 +1,6 @@
 /* trustdb.c
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
-#include <ctype.h>
 #include <assert.h>
+
+#ifndef DISABLE_REGEX
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
+#ifdef USE_GNU_REGEX
+#include "_regex.h"
+#else
+#include <regex.h>
+#endif
+#endif /* !DISABLE_REGEX */
 
 #include "errors.h"
 #include "iobuf.h"
 #include "keydb.h"
 #include "memory.h"
 #include "util.h"
-#include "trustdb.h"
 #include "options.h"
 #include "packet.h"
 #include "main.h"
 #include "i18n.h"
 #include "tdbio.h"
+#include "trustdb.h"
 
-#if MAX_FINGERPRINT_LEN > 20
-  #error Must change structure of trustdb
-#endif
-
-struct keyid_list {
-    struct keyid_list *next;
-    u32 keyid[2];
-};
-
-struct local_id_item {
-    struct local_id_item *next;
-    ulong lid;
-    unsigned flag;
-};
-
-struct local_id_table {
-    struct local_id_table *next; /* only used to keep a list of unused tables */
-    struct local_id_item *items[16];
-};
-
-
-typedef struct local_id_table *LOCAL_ID_TABLE;
-
-
-typedef struct trust_info TRUST_INFO;
-struct trust_info {
-    ulong    lid;
-    byte     otrust; /* ownertrust (assigned trust) */
-    byte     trust;  /* calculated trust (validity) */
-};
 
-typedef struct trust_seg_list *TRUST_SEG_LIST;
-struct trust_seg_list {
-    TRUST_SEG_LIST next;
-    int  pathlen;
-    TRUST_INFO path[1];
+/*
+ * A structure to store key identification as well as some stuff needed
+ * for validation 
+ */
+struct key_item {
+  struct key_item *next;
+  unsigned int ownertrust,min_ownertrust;
+  byte trust_depth;
+  byte trust_value;
+  char *trust_regexp;
+  u32 kid[2];
 };
 
 
-struct enum_cert_paths_ctx {
-   int init;
-   TRUST_SEG_LIST tsl_head;
-   TRUST_SEG_LIST tsl;
-   int idx;
-};
-
+typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
 
-struct recno_list_struct {
-    struct recno_list_struct *next;
-    ulong recno;
-    int type;
+/*
+ * Structure to keep track of keys, this is used as an array wherre
+ * the item right after the last one has a keyblock set to NULL. 
+ * Maybe we can drop this thing and replace it by key_item
+ */
+struct key_array {
+  KBNODE keyblock;
 };
-typedef struct recno_list_struct *RECNO_LIST;
-
-
-static int walk_sigrecs( SIGREC_CONTEXT *c );
 
-static LOCAL_ID_TABLE new_lid_table(void);
-static void release_lid_table( LOCAL_ID_TABLE tbl );
-static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
-static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
 
-static void print_user_id( const char *text, u32 *keyid );
-static void sort_tsl_list( TRUST_SEG_LIST *trust_seg_list );
-static int list_sigs( ulong pubkey_id );
-static int do_check( TRUSTREC *drec, unsigned *trustlevel );
-static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
+/* control information for the trust DB */
+static struct {
+    int init;
+    int level;
+    char *dbname;
+} trustdb_args;
 
-static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig );
-static void upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
-                TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
-                TRUSTREC *urec, const byte *uidhash, int revoke );
+/* some globals */
+static struct key_item *user_utk_list; /* temp. used to store --trusted-keys */
+static struct key_item *utk_list;      /* all ultimately trusted keys */
 
-static struct keyid_list *trusted_key_list;
-
-/* a table used to keep track of ultimately trusted keys
- * which are the ones from our secrings and the trusted keys */
-static LOCAL_ID_TABLE ultikey_table;
-
-/* list of unused lid items and tables */
-static LOCAL_ID_TABLE unused_lid_tables;
-static struct local_id_item *unused_lid_items;
-
-
-#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
-                     (a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
+static int pending_check_trustdb;
 
+static int validate_keys (int interactive);
 
 \f
 /**********************************************
- ***********  record read write  **************
+ ************* some helpers *******************
  **********************************************/
 
+static struct key_item *
+new_key_item (void)
+{
+  struct key_item *k;
+  
+  k = m_alloc_clear (sizeof *k);
+  return k;
+}
+
 static void
-die_invalid_db()
+release_key_items (struct key_item *k)
 {
-    log_error(_(
-       "The trustdb is corrupted; please run \"gpgm --fix-trustdb\".\n") );
-    g10_exit(2);
+  struct key_item *k2;
+
+  for (; k; k = k2)
+    {
+      k2 = k->next;
+      m_free (k->trust_regexp);
+      m_free (k);
+    }
 }
 
-/****************
- * Read a record but die if it does not exist
+/*
+ * For fast keylook up we need a hash table.  Each byte of a KeyIDs
+ * should be distributed equally over the 256 possible values (except
+ * for v3 keyIDs but we consider them as not important here). So we
+ * can just use 10 bits to index a table of 1024 key items. 
+ * Possible optimization: Don not use key_items but other hash_table when the
+ * duplicates lists gets too large. 
  */
-static void
-read_record( ulong recno, TRUSTREC *rec, int rectype )
+static KeyHashTable 
+new_key_hash_table (void)
 {
-    int rc = tdbio_read_record( recno, rec, rectype );
-    if( !rc )
-       return;
-    log_error(_("trust record %lu, req type %d: read failed: %s\n"),
-                                   recno, rectype,  g10_errstr(rc) );
-    die_invalid_db();
+  struct key_item **tbl;
+
+  tbl = m_alloc_clear (1024 * sizeof *tbl);
+  return tbl;
 }
 
+static void
+release_key_hash_table (KeyHashTable tbl)
+{
+  int i;
+
+  if (!tbl)
+    return;
+  for (i=0; i < 1024; i++)
+    release_key_items (tbl[i]);
+  m_free (tbl);
+}
 
-/****************
- * Wirte a record but die on error
+/* 
+ * Returns: True if the keyID is in the given hash table
  */
-static void
-write_record( TRUSTREC *rec )
+static int
+test_key_hash_table (KeyHashTable tbl, u32 *kid)
 {
-    int rc = tdbio_write_record( rec );
-    if( !rc )
-       return;
-    log_error(_("trust record %lu, type %d: write failed: %s\n"),
-                           rec->recnum, rec->rectype, g10_errstr(rc) );
-    die_invalid_db();
+  struct key_item *k;
+
+  for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
+    if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+      return 1;
+  return 0;
 }
 
-/****************
- * Delete a record but die on error
+/*
+ * Add a new key to the hash table.  The key is identified by its key ID.
  */
 static void
-delete_record( ulong recno )
+add_key_hash_table (KeyHashTable tbl, u32 *kid)
 {
-    int rc = tdbio_delete_record( recno );
-    if( !rc )
-       return;
-    log_error(_("trust record %lu: delete failed: %s\n"),
-                                             recno, g10_errstr(rc) );
-    die_invalid_db();
+  struct key_item *k, *kk;
+
+  for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
+    if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+      return; /* already in table */
+  
+  kk = new_key_item ();
+  kk->kid[0] = kid[0];
+  kk->kid[1] = kid[1];
+  kk->next = tbl[(kid[1] & 0x03ff)];
+  tbl[(kid[1] & 0x03ff)] = kk;
 }
 
-/****************
- * sync the db
+/*
+ * Release a key_array
  */
 static void
-do_sync( )
+release_key_array ( struct key_array *keys )
 {
-    int rc = tdbio_sync();
-    if( !rc )
-       return;
-    log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
-    g10_exit(2);
-}
+    struct key_array *k;
 
+    if (keys) {
+        for (k=keys; k->keyblock; k++)
+            release_kbnode (k->keyblock);
+        m_free (keys);
+    }
+}
 
 \f
-/**********************************************
- ************* list helpers *******************
- **********************************************/
+/*********************************************
+ **********  Initialization  *****************
+ *********************************************/
 
-/****************
- * Insert a new item into a recno list
+
+
+/*
+ * Used to register extra ultimately trusted keys - this has to be done
+ * before initializing the validation module.
+ * FIXME: Should be replaced by a function to add those keys to the trustdb.
  */
-static void
-ins_recno_list( RECNO_LIST *head, ulong recno, int type )
+void
+register_trusted_keyid(u32 *keyid)
 {
-    RECNO_LIST item = m_alloc( sizeof *item );
+  struct key_item *k;
 
-    item->recno = recno;
-    item->type = type;
-    item->next = *head;
-    *head = item;
+  k = new_key_item ();
+  k->kid[0] = keyid[0];
+  k->kid[1] = keyid[1];
+  k->next = user_utk_list;
+  user_utk_list = k;
 }
 
-static RECNO_LIST
-qry_recno_list( RECNO_LIST list, ulong recno, int type )
+void
+register_trusted_key( const char *string )
 {
-    for( ; list; list = list->next ) {
-       if( list->recno == recno && (!type || list->type == type) )
-           return list;
+  KEYDB_SEARCH_DESC desc;
+
+  if (classify_user_id (string, &desc) != KEYDB_SEARCH_MODE_LONG_KID )
+    {
+      log_error(_("`%s' is not a valid long keyID\n"), string );
+      return;
     }
-    return NULL;
+
+  register_trusted_keyid(desc.u.kid);
+}
+
+/*
+ * Helper to add a key to the global list of ultimately trusted keys.
+ * Retruns: true = inserted, false = already in in list.
+ */
+static int
+add_utk (u32 *kid)
+{
+  struct key_item *k;
+
+  for (k = utk_list; k; k = k->next) 
+    {
+      if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+        {
+          return 0;
+        }
+    }
+
+  k = new_key_item ();
+  k->kid[0] = kid[0];
+  k->kid[1] = kid[1];
+  k->ownertrust = TRUST_ULTIMATE;
+  k->next = utk_list;
+  utk_list = k;
+  if( opt.verbose > 1 )
+    log_info(_("key %s: accepted as trusted key\n"), keystr(kid));
+  return 1;
 }
 
 
+/****************
+ * Verify that all our secret keys are usable and put them into the utk_list.
+ */
 static void
-rel_recno_list( RECNO_LIST *head )
+verify_own_keys(void)
 {
-    RECNO_LIST r, r2;
+  TRUSTREC rec;
+  ulong recnum;
+  int rc;
+  struct key_item *k;
+
+  if (utk_list)
+    return;
+
+  /* scan the trustdb to find all ultimately trusted keys */
+  for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ ) 
+    {
+      if ( rec.rectype == RECTYPE_TRUST 
+           && (rec.r.trust.ownertrust & TRUST_MASK) == TRUST_ULTIMATE)
+        {
+            byte *fpr = rec.r.trust.fingerprint;
+            int fprlen;
+            u32 kid[2];
+            
+            /* Problem: We do only use fingerprints in the trustdb but
+             * we need the keyID here to indetify the key; we can only
+             * use that ugly hack to distinguish between 16 and 20
+             * butes fpr - it does not work always so we better change
+             * the whole validation code to only work with
+             * fingerprints */
+            fprlen = (!fpr[16] && !fpr[17] && !fpr[18] && !fpr[19])? 16:20;
+            keyid_from_fingerprint (fpr, fprlen, kid);
+            if (!add_utk (kid))
+             log_info(_("key %s occurs more than once in the trustdb\n"),
+                      keystr(kid));
+        }
+    }
+
+  /* Put any --trusted-key keys into the trustdb */
+  for (k = user_utk_list; k; k = k->next) 
+    {
+      if ( add_utk (k->kid) ) 
+        { /* not yet in trustDB as ultimately trusted */
+          PKT_public_key pk;
+
+          memset (&pk, 0, sizeof pk);
+          rc = get_pubkey (&pk, k->kid);
+          if (rc)
+           log_info(_("key %s: no public key for trusted key - skipped\n"),
+                    keystr(k->kid));
+          else
+           {
+             update_ownertrust (&pk,
+                                ((get_ownertrust (&pk) & ~TRUST_MASK)
+                                 | TRUST_ULTIMATE ));
+             release_public_key_parts (&pk);
+           }
 
-    for(r = *head; r; r = r2 ) {
-       r2 = r->next;
-       m_free(r);
+          log_info (_("key %s marked as ultimately trusted\n"),keystr(k->kid));
+        }
     }
-    *head = NULL;
+
+  /* release the helper table table */
+  release_key_items (user_utk_list);
+  user_utk_list = NULL;
+  return;
 }
 
-static LOCAL_ID_TABLE
-new_lid_table(void)
-{
-    LOCAL_ID_TABLE a;
+\f
+/*********************************************
+ *********** TrustDB stuff *******************
+ *********************************************/
 
-    a = unused_lid_tables;
-    if( a ) {
-       unused_lid_tables = a->next;
-       memset( a, 0, sizeof *a );
+/*
+ * Read a record but die if it does not exist
+ */
+static void
+read_record (ulong recno, TRUSTREC *rec, int rectype )
+{
+  int rc = tdbio_read_record (recno, rec, rectype);
+  if (rc)
+    {
+      log_error(_("trust record %lu, req type %d: read failed: %s\n"),
+                recno, rec->rectype, g10_errstr(rc) );
+      tdbio_invalid();
+    }
+  if (rectype != rec->rectype)
+    {
+      log_error(_("trust record %lu is not of requested type %d\n"),
+                rec->recnum, rectype);
+      tdbio_invalid();
     }
-    else
-       a = m_alloc_clear( sizeof *a );
-    return a;
 }
 
+/*
+ * Write a record and die on error
+ */
 static void
-release_lid_table( LOCAL_ID_TABLE tbl )
+write_record (TRUSTREC *rec)
 {
-    struct local_id_item *a, *a2;
-    int i;
-
-    for(i=0; i < 16; i++ ) {
-       for(a=tbl->items[i]; a; a = a2 ) {
-           a2 = a->next;
-           a->next = unused_lid_items;
-           unused_lid_items = a;
-       }
+  int rc = tdbio_write_record (rec);
+  if (rc)
+    {
+      log_error(_("trust record %lu, type %d: write failed: %s\n"),
+                           rec->recnum, rec->rectype, g10_errstr(rc) );
+      tdbio_invalid();
     }
-    tbl->next = unused_lid_tables;
-    unused_lid_tables = tbl;
 }
 
-/****************
- * Add a new item to the table or return 1 if we already have this item
+/*
+ * sync the TrustDb and die on error
  */
-static int
-ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag )
+static void
+do_sync(void)
 {
-    struct local_id_item *a;
-
-    for( a = tbl->items[lid & 0x0f]; a; a = a->next )
-       if( a->lid == lid )
-           return 1;
-    a = unused_lid_items;
-    if( a )
-       unused_lid_items = a->next;
-    else
-       a = m_alloc( sizeof *a );
-    a->lid = lid;
-    a->flag = flag;
-    a->next = tbl->items[lid & 0x0f];
-    tbl->items[lid & 0x0f] = a;
-    return 0;
+    int rc = tdbio_sync ();
+    if(rc)
+      {
+        log_error (_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
+        g10_exit(2);
+      }
 }
 
-static int
-qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag )
+static const char *
+trust_model_string(void)
 {
-    struct local_id_item *a;
-
-    for( a = tbl->items[lid & 0x0f]; a; a = a->next )
-       if( a->lid == lid ) {
-           if( flag )
-               *flag = a->flag;
-           return 0;
-       }
-    return -1;
+  switch(opt.trust_model)
+    {
+    case TM_CLASSIC:  return "classic";
+    case TM_PGP:      return "PGP";
+    case TM_EXTERNAL: return "external";
+    case TM_ALWAYS:   return "always";
+    case TM_DIRECT:   return "direct";
+    default:          return "unknown";
+    }
 }
 
-
-
 /****************
- * Return the keyid from the primary key identified by LID.
+ * Perform some checks over the trustdb
+ *  level 0: only open the db
+ *       1: used for initial program startup
  */
 int
-keyid_from_lid( ulong lid, u32 *keyid )
+setup_trustdb( int level, const char *dbname )
 {
-    TRUSTREC rec;
-    int rc;
-
-    rc = tdbio_read_record( lid, &rec, 0 );
-    if( rc ) {
-       log_error(_("error reading dir record for LID %lu: %s\n"),
-                                                   lid, g10_errstr(rc));
-       return G10ERR_TRUSTDB;
-    }
-    if( rec.rectype == RECTYPE_SDIR )
+    /* just store the args */
+    if( trustdb_args.init )
        return 0;
-    if( rec.rectype != RECTYPE_DIR ) {
-       log_error(_("lid %lu: expected dir record, got type %d\n"),
-                                                   lid, rec.rectype );
-       return G10ERR_TRUSTDB;
-    }
-    if( !rec.r.dir.keylist ) {
-       log_error(_("no primary key for LID %lu\n"), lid );
-       return G10ERR_TRUSTDB;
-    }
-    rc = tdbio_read_record( rec.r.dir.keylist, &rec, RECTYPE_KEY );
-    if( rc ) {
-       log_error(_("error reading primary key for LID %lu: %s\n"),
-                                                   lid, g10_errstr(rc));
-       return G10ERR_TRUSTDB;
-    }
-    keyid_from_fingerprint( rec.r.key.fingerprint, rec.r.key.fingerprint_len,
-                           keyid );
-
+    trustdb_args.level = level;
+    trustdb_args.dbname = dbname? m_strdup(dbname): NULL;
     return 0;
 }
 
-
-ulong
-lid_from_keyblock( KBNODE keyblock )
+void
+init_trustdb()
 {
-    KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
-    PKT_public_key *pk;
-    if( !node )
-       BUG();
-    pk = node->pkt->pkt.public_key;
-    if( !pk->local_id ) {
-       TRUSTREC rec;
-
-       get_dir_record( pk, &rec );
+  int level = trustdb_args.level;
+  const char* dbname = trustdb_args.dbname;
+
+  if( trustdb_args.init )
+    return;
+
+  trustdb_args.init = 1;
+
+  if(level==0 || level==1)
+    {
+      int rc = tdbio_set_dbname( dbname, !!level );
+      if( rc )
+       log_fatal("can't init trustdb: %s\n", g10_errstr(rc) );
     }
-    return pk->local_id;
-}
+  else
+    BUG();
 
+  if(opt.trust_model==TM_AUTO)
+    {
+      /* Try and set the trust model off of whatever the trustdb says
+        it is. */
+      opt.trust_model=tdbio_read_model();
 
-\f
-/****************
- * Walk through the signatures of a public key.
- * The caller must provide a context structure, with all fields set
- * to zero, but the local_id field set to the requested key;
- * This function does not change this field.  On return the context
- * is filled with the local-id of the signature and the signature flag.
- * No fields should be changed (clearing all fields and setting
- * pubkeyid is okay to continue with an other pubkey)
- * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
- */
-static int
-walk_sigrecs( SIGREC_CONTEXT *c )
-{
-    TRUSTREC *r;
-    ulong rnum;
-
-    if( c->ctl.eof )
-       return -1;
-    r = &c->ctl.rec;
-    if( !c->ctl.init_done ) {
-       c->ctl.init_done = 1;
-       read_record( c->lid, r, 0 );
-       if( r->rectype != RECTYPE_DIR ) {
-           c->ctl.eof = 1;
-           return -1;  /* return eof */
+      /* Sanity check this ;) */
+      if(opt.trust_model!=TM_CLASSIC
+        && opt.trust_model!=TM_PGP
+        && opt.trust_model!=TM_EXTERNAL)
+       {
+         log_info(_("unable to use unknown trust model (%d) - "
+                    "assuming %s trust model\n"),opt.trust_model,"PGP");
+         opt.trust_model=TM_PGP;
        }
-       c->ctl.nextuid = r->r.dir.uidlist;
-       /* force a read */
-       c->ctl.index = SIGS_PER_RECORD;
-       r->r.sig.next = 0;
+
+      if(opt.verbose)
+       log_info(_("using %s trust model\n"),trust_model_string());
     }
 
-    /* need a loop to skip over deleted sigs */
-    do {
-       if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
-           rnum = r->r.sig.next;
-           if( !rnum && c->ctl.nextuid ) { /* read next uid record */
-               read_record( c->ctl.nextuid, r, RECTYPE_UID );
-               c->ctl.nextuid = r->r.uid.next;
-               rnum = r->r.uid.siglist;
-           }
-           if( !rnum ) {
-               c->ctl.eof = 1;
-               return -1;  /* return eof */
-           }
-           read_record( rnum, r, RECTYPE_SIG );
-           if( r->r.sig.lid != c->lid ) {
-               log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
-               c->ctl.eof = 1;
-               die_invalid_db();
-           }
-           c->ctl.index = 0;
-       }
-    } while( !r->r.sig.sig[c->ctl.index++].lid );
+  if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+    {
+      /* Verify the list of ultimately trusted keys and move the
+        --trusted-keys list there as well. */
+      if(level==1)
+       verify_own_keys();
 
-    c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
-    c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
-    return 0;
+      if(!tdbio_db_matches_options())
+       pending_check_trustdb=1;
+    }
 }
 
 
-
-\f
 /***********************************************
- ************* Trust  stuff  ******************
+ ************* Print helpers   ****************
  ***********************************************/
 
+/****************
+ * This function returns a letter for a trustvalue  Trust flags
+ * are ignore.
+ */
 static int
-trust_letter( unsigned value )
+trust_letter (unsigned int value)
 {
-    switch( value ) {
-      case TRUST_UNKNOWN:   return '-';
-      case TRUST_EXPIRED:   return 'e';
-      case TRUST_UNDEFINED: return 'q';
-      case TRUST_NEVER:     return 'n';
-      case TRUST_MARGINAL:  return 'm';
-      case TRUST_FULLY:     return 'f';
-      case TRUST_ULTIMATE:  return 'u';
-      default:             return  0 ;
+  switch( (value & TRUST_MASK) ) 
+    {
+    case TRUST_UNKNOWN:   return '-';
+    case TRUST_EXPIRED:   return 'e';
+    case TRUST_UNDEFINED: return 'q';
+    case TRUST_NEVER:     return 'n';
+    case TRUST_MARGINAL:  return 'm';
+    case TRUST_FULLY:     return 'f';
+    case TRUST_ULTIMATE:  return 'u';
+    default:              return '?';
     }
 }
 
-
-void
-register_trusted_key( const char *string )
+/* NOTE TO TRANSLATOR: these strings are similar to those in
+   trust_value_to_string(), but are a fixed length.  This is needed to
+   make attractive information listings where columns line up
+   properly.  The value "10" should be the length of the strings you
+   choose to translate to.  This is the length in printable columns.
+   It gets passed to atoi() so everything after the number is
+   essentially a comment and need not be translated.  Either key and
+   uid are both NULL, or neither are NULL. */
+const char *
+uid_trust_string_fixed(PKT_public_key *key,PKT_user_id *uid)
 {
-    u32 keyid[2];
-    struct keyid_list *r;
+  if(!key && !uid)
+    return _("10 translator see trustdb.c:uid_trust_string_fixed");
+  else if(uid->is_revoked || (key && key->is_revoked))
+    return                         _("[ revoked]");
+  else if(uid->is_expired)
+    return                         _("[ expired]");
+  else if(key)
+    switch(get_validity(key,uid)&TRUST_MASK)
+      {
+      case TRUST_UNKNOWN:   return _("[ unknown]");
+      case TRUST_EXPIRED:   return _("[ expired]");
+      case TRUST_UNDEFINED: return _("[  undef ]");
+      case TRUST_MARGINAL:  return _("[marginal]");
+      case TRUST_FULLY:     return _("[  full  ]");
+      case TRUST_ULTIMATE:  return _("[ultimate]");
+      }
+
+  return "err";
+}
 
-    if( classify_user_id( string, keyid, NULL, NULL, NULL ) != 11 ) {
-       log_error(_("'%s' is not a valid long keyID\n"), string );
-       return;
+/* The strings here are similar to those in
+   pkclist.c:do_edit_ownertrust() */
+const char *
+trust_value_to_string (unsigned int value)
+{
+  switch( (value & TRUST_MASK) ) 
+    {
+    case TRUST_UNKNOWN:   return _("unknown");
+    case TRUST_EXPIRED:   return _("expired");
+    case TRUST_UNDEFINED: return _("undefined");
+    case TRUST_NEVER:     return _("never");
+    case TRUST_MARGINAL:  return _("marginal");
+    case TRUST_FULLY:     return _("full");
+    case TRUST_ULTIMATE:  return _("ultimate");
+    default:              return "err";
     }
+}
 
-    for( r = trusted_key_list; r; r = r->next )
-       if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] )
-           return;
-    r = m_alloc( sizeof *r );
-    r->keyid[0] = keyid[0];
-    r->keyid[1] = keyid[1];
-    r->next = trusted_key_list;
-    trusted_key_list = r;
+int
+string_to_trust_value (const char *str)
+{
+  if(ascii_strcasecmp(str,"undefined")==0)
+    return TRUST_UNDEFINED;
+  else if(ascii_strcasecmp(str,"never")==0)
+    return TRUST_NEVER;
+  else if(ascii_strcasecmp(str,"marginal")==0)
+    return TRUST_MARGINAL;
+  else if(ascii_strcasecmp(str,"full")==0)
+    return TRUST_FULLY;
+  else if(ascii_strcasecmp(str,"ultimate")==0)
+    return TRUST_ULTIMATE;
+  else
+    return -1;
 }
 
 /****************
- * Verify that all our public keys are in the trustdb.
+ * Recreate the WoT but do not ask for new ownertrusts.  Special
+ * feature: In batch mode and without a forced yes, this is only done
+ * when a check is due.  This can be used to run the check from a crontab
  */
-static int
-verify_own_keys()
+void
+check_trustdb ()
 {
-    int rc;
-    void *enum_context = NULL;
-    PKT_secret_key *sk = m_alloc_clear( sizeof *sk );
-    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-    u32 keyid[2];
-    struct keyid_list *kl;
-
-    /* put the trusted keys into the trusted key table */
-    for( kl = trusted_key_list; kl; kl = kl->next ) {
-       keyid[0] = kl->keyid[0];
-       keyid[1] = kl->keyid[1];
-       /* get the public key */
-       memset( pk, 0, sizeof *pk );
-       rc = get_pubkey( pk, keyid );
-       if( rc ) {
-           log_info(_("key %08lX: no public key for trusted key - skipped\n"),
-                                                           (ulong)keyid[1] );
-       }
-       else {
-           /* make sure that the pubkey is in the trustdb */
-           rc = query_trust_record( pk );
-           if( rc == -1 ) { /* put it into the trustdb */
-               rc = insert_trust_record( pk );
-               if( rc ) {
-                   log_error(_("key %08lX: can't put it into the trustdb\n"),
-                                                       (ulong)keyid[1] );
-               }
-           }
-           else if( rc ) {
-               log_error(_("key %08lX: query record failed\n"),
-                                                       (ulong)keyid[1] );
-           }
-           else {
-               if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
-                   log_error(_("key %08lX: already in trusted key table\n"),
-                                                         (ulong)keyid[1]);
-               else if( opt.verbose > 1 )
-                   log_info(_("key %08lX: accepted as trusted key.\n"),
-                                                         (ulong)keyid[1]);
+  init_trustdb();
+  if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+    {
+      if (opt.batch && !opt.answer_yes)
+       {
+         ulong scheduled;
+
+         scheduled = tdbio_read_nextcheck ();
+         if (!scheduled)
+           {
+             log_info (_("no need for a trustdb check\n"));
+             return;
            }
-       }
-       release_public_key_parts( pk );
-    }
-
-    while( !(rc=enum_secret_keys( &enum_context, sk, 0 ) ) ) {
-       int have_pk = 0;
-
-       keyid_from_sk( sk, keyid );
-
-       if( DBG_TRUST )
-           log_debug("key %08lX: checking secret key\n", (ulong)keyid[1] );
-
-       if( is_secret_key_protected( sk ) < 1 )
-           log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
-                                                           (ulong)keyid[1] );
-
-       for( kl = trusted_key_list; kl; kl = kl->next ) {
-           if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
-               goto skip; /* already in trusted key table */
-       }
 
-       /* see whether we can access the public key of this secret key */
-       memset( pk, 0, sizeof *pk );
-       rc = get_pubkey( pk, keyid );
-       if( rc ) {
-           log_info(_("key %08lX: secret key without public key - skipped\n"),
-                                                           (ulong)keyid[1] );
-           goto skip;
-       }
-       have_pk=1;
-
-       if( cmp_public_secret_key( pk, sk ) ) {
-           log_info(_("key %08lX: secret and public key don't match\n"),
-                                                           (ulong)keyid[1] );
-           goto skip;
-       }
-
-       /* make sure that the pubkey is in the trustdb */
-       rc = query_trust_record( pk );
-       if( rc == -1 ) { /* put it into the trustdb */
-           rc = insert_trust_record( pk );
-           if( rc ) {
-               log_error(_("key %08lX: can't put it into the trustdb\n"),
-                                                           (ulong)keyid[1] );
-               goto skip;
+         if (scheduled > make_timestamp ())
+           {
+             log_info (_("next trustdb check due at %s\n"),
+                       strtimestamp (scheduled));
+             return;
            }
        }
-       else if( rc ) {
-           log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
-           goto skip;
 
-       }
-
-       if( DBG_TRUST )
-           log_debug("key %08lX.%lu: stored into ultikey_table\n",
-                                   (ulong)keyid[1], pk->local_id );
-       if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
-           log_error(_("key %08lX: already in trusted key table\n"),
-                                                       (ulong)keyid[1]);
-       else if( opt.verbose > 1 )
-           log_info(_("key %08lX: accepted as trusted key.\n"),
-                                                       (ulong)keyid[1]);
-      skip:
-       release_secret_key_parts( sk );
-       if( have_pk )
-           release_public_key_parts( pk );
-    }
-    if( rc != -1 )
-       log_error(_("enumerate secret keys failed: %s\n"), g10_errstr(rc) );
-    else
-       rc = 0;
-
-    /* release the trusted keyid table */
-    {  struct keyid_list *kl2;
-       for( kl = trusted_key_list; kl; kl = kl2 ) {
-           kl2 = kl->next;
-           m_free( kl );
-       }
-       trusted_key_list = NULL;
+      validate_keys (0);
     }
-
-    enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
-    free_secret_key( sk );
-    free_public_key( pk );
-    return rc;
+  else
+    log_info (_("no need for a trustdb check with `%s' trust model\n"),
+             trust_model_string());
 }
 
 
-static void
-print_user_id( const char *text, u32 *keyid )
+/*
+ * Recreate the WoT. 
+ */
+void
+update_trustdb()
 {
-    char *p;
-    size_t n;
+  init_trustdb();
+  if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+    validate_keys (1);
+  else
+    log_info (_("no need for a trustdb update with `%s' trust model\n"),
+             trust_model_string());
+}
 
-    p = get_user_id( keyid, &n );
-    if( *text ) {
-       fputs( text, stdout);
-       putchar(' ');
-    }
-    putchar('\"');
-    print_string( stdout, p, n, 0 );
-    putchar('\"');
-    putchar('\n');
-    m_free(p);
+void
+revalidation_mark (void)
+{
+  init_trustdb();
+  /* we simply set the time for the next check to 1 (far back in 1970)
+   * so that a --update-trustdb will be scheduled */
+  if (tdbio_write_nextcheck (1))
+      do_sync ();
+  pending_check_trustdb = 1;
 }
 
-#if 0
-static int
-print_keyid( FILE *fp, ulong lid )
+int
+trustdb_pending_check(void)
 {
-    u32 ki[2];
-    if( keyid_from_lid( lid, ki ) )
-       return fprintf(fp, "????????.%lu", lid );
-    else
-       return fprintf(fp, "%08lX.%lu", (ulong)ki[1], lid );
+  return pending_check_trustdb;
 }
 
-static int
-print_trust( FILE *fp, unsigned trust )
+/* If the trustdb is dirty, and we're interactive, update it.
+   Otherwise, check it unless no-auto-check-trustdb is set. */
+void
+trustdb_check_or_update(void)
 {
-    int c;
-    switch( trust ) {
-      case TRUST_UNKNOWN:   c = 'o'; break;
-      case TRUST_EXPIRED:   c = 'e'; break;
-      case TRUST_UNDEFINED: c = 'q'; break;
-      case TRUST_NEVER:     c = 'n'; break;
-      case TRUST_MARGINAL:  c = 'm'; break;
-      case TRUST_FULLY:     c = 'f'; break;
-      case TRUST_ULTIMATE:  c = 'u'; break;
-      default: fprintf(fp, "%02x", trust ); return 2;
+  if(trustdb_pending_check())
+    {
+      if(opt.interactive)
+       update_trustdb();
+      else if(!opt.no_auto_check_trustdb)
+       check_trustdb();
     }
-    putc(c, fp);
-    return 1;
 }
-#endif
 
-static int
-print_sigflags( FILE *fp, unsigned flags )
+void
+read_trust_options(byte *trust_model,ulong *created,ulong *nextcheck,
+                  byte *marginals,byte *completes,byte *cert_depth)
 {
-    if( flags & SIGF_CHECKED ) {
-       fprintf(fp,"%c%c%c",
-          (flags & SIGF_VALID)   ? 'V':'-',
-          (flags & SIGF_EXPIRED) ? 'E':'-',
-          (flags & SIGF_REVOKED) ? 'R':'-');
-    }
-    else if( flags & SIGF_NOPUBKEY)
-       fputs("?--", fp);
-    else
-       fputs("---", fp);
-    return 3;
+  TRUSTREC opts;
+
+  init_trustdb();
+
+  read_record(0,&opts,RECTYPE_VER);
+
+  if(trust_model)
+    *trust_model=opts.r.ver.trust_model;
+  if(created)
+    *created=opts.r.ver.created;
+  if(nextcheck)
+    *nextcheck=opts.r.ver.nextcheck;
+  if(marginals)
+    *marginals=opts.r.ver.marginals;
+  if(completes)
+    *completes=opts.r.ver.completes;
+  if(cert_depth)
+    *cert_depth=opts.r.ver.cert_depth;
 }
 
-/* (a non-recursive algorithm would be easier) */
-static int
-do_list_sigs( ulong root, ulong pk_lid, int depth,
-             LOCAL_ID_TABLE lids, unsigned *lineno )
+/***********************************************
+ ***********  Ownertrust et al. ****************
+ ***********************************************/
+
+static int 
+read_trust_record (PKT_public_key *pk, TRUSTREC *rec)
 {
-    SIGREC_CONTEXT sx;
-    int rc;
-    u32 keyid[2];
-
-    memset( &sx, 0, sizeof sx );
-    sx.lid = pk_lid;
-    for(;;) {
-       rc = walk_sigrecs( &sx ); /* should we replace it and use */
-       if( rc )                  /* use a loop like in collect_paths ??*/
-           break;
-       rc = keyid_from_lid( sx.sig_lid, keyid );
-       if( rc ) {
-           printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
-           print_sigflags( stdout, sx.sig_flag );
-           putchar('\n');
-           ++*lineno;
-       }
-       else {
-           printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
-                             (ulong)keyid[1], sx.sig_lid );
-           print_sigflags( stdout, sx.sig_flag );
-           putchar(' ');
-           /* check whether we already checked this pk_lid */
-           if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
-               print_user_id("[ultimately trusted]", keyid);
-               ++*lineno;
-           }
-           else if( sx.sig_lid == pk_lid ) {
-               printf("[self-signature]\n");
-               ++*lineno;
-           }
-           else if( sx.sig_lid == root ) {
-               printf("[closed]\n");
-               ++*lineno;
-           }
-           else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
-               unsigned refline;
-               qry_lid_table_flag( lids, sx.sig_lid, &refline );
-               printf("[see line %u]\n", refline);
-               ++*lineno;
-           }
-           else if( depth+1 >= MAX_LIST_SIGS_DEPTH  ) {
-               print_user_id( "[too deeply nested]", keyid );
-               ++*lineno;
-           }
-           else {
-               print_user_id( "", keyid );
-               ++*lineno;
-               rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
-               if( rc )
-                   break;
-           }
-       }
-    }
-    return rc==-1? 0 : rc;
+  int rc;
+  
+  init_trustdb();
+  rc = tdbio_search_trust_bypk (pk, rec);
+  if (rc == -1)
+    return -1; /* no record yet */
+  if (rc) 
+    {
+      log_error ("trustdb: searching trust record failed: %s\n",
+                 g10_errstr (rc));
+      return rc; 
+    }
+      
+  if (rec->rectype != RECTYPE_TRUST)
+    {
+      log_error ("trustdb: record %lu is not a trust record\n",
+                 rec->recnum);
+      return G10ERR_TRUSTDB; 
+    }      
+  
+  return 0;
 }
 
 /****************
- * List all signatures of a public key
+ * Return the assigned ownertrust value for the given public key.
+ * The key should be the primary key.
  */
-static int
-list_sigs( ulong pubkey_id )
+unsigned int 
+get_ownertrust ( PKT_public_key *pk)
 {
-    int rc;
-    u32 keyid[2];
-    LOCAL_ID_TABLE lids;
-    unsigned lineno = 1;
-
-    rc = keyid_from_lid( pubkey_id, keyid );
-    if( rc )
-       return rc;
-    printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
-    print_user_id("", keyid);
-    printf("----------------------\n");
-
-    lids = new_lid_table();
-    rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
-    putchar('\n');
-    release_lid_table(lids);
-    return rc;
+  TRUSTREC rec;
+  int rc;
+  
+  rc = read_trust_record (pk, &rec);
+  if (rc == -1)
+    return TRUST_UNKNOWN; /* no record yet */
+  if (rc) 
+    {
+      tdbio_invalid ();
+      return rc; /* actually never reached */
+    }
+
+  return rec.r.trust.ownertrust;
 }
 
-/****************
- * List all records of a public key
+unsigned int 
+get_min_ownertrust (PKT_public_key *pk)
+{
+  TRUSTREC rec;
+  int rc;
+  
+  rc = read_trust_record (pk, &rec);
+  if (rc == -1)
+    return TRUST_UNKNOWN; /* no record yet */
+  if (rc) 
+    {
+      tdbio_invalid ();
+      return rc; /* actually never reached */
+    }
+
+  return rec.r.trust.min_ownertrust;
+}
+
+/*
+ * Same as get_ownertrust but this takes the minimum ownertrust value
+ * into into account, and will bump up the value as needed.
  */
 static int
-list_records( ulong lid )
+get_ownertrust_with_min (PKT_public_key *pk)
 {
-    int rc;
-    TRUSTREC dr, ur, rec;
-    ulong recno;
-
-    rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
-    if( rc ) {
-       log_error(_("lid %lu: read dir record failed: %s\n"),
-                                               lid, g10_errstr(rc));
-       return rc;
-    }
-    tdbio_dump_record( &dr, stdout );
-
-    for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
-       rc = tdbio_read_record( recno, &rec, 0 );
-       if( rc ) {
-           log_error(_("lid %lu: read key record failed: %s\n"),
-                                               lid, g10_errstr(rc));
-           return rc;
-       }
-       tdbio_dump_record( &rec, stdout );
-    }
-
-    for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
-       rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
-       if( rc ) {
-           log_error(_("lid %lu: read uid record failed: %s\n"),
-                                               lid, g10_errstr(rc));
-           return rc;
-       }
-       tdbio_dump_record( &ur, stdout );
-       /* preference records */
-       for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
-           rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
-           if( rc ) {
-               log_error(_("lid %lu: read pref record failed: %s\n"),
-                                                   lid, g10_errstr(rc));
-               return rc;
-           }
-           tdbio_dump_record( &rec, stdout );
-       }
-       /* sig records */
-       for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
-           rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
-           if( rc ) {
-               log_error(_("lid %lu: read sig record failed: %s\n"),
-                                                   lid, g10_errstr(rc));
-               return rc;
-           }
-           tdbio_dump_record( &rec, stdout );
-       }
-    }
-
-    /* add cache record dump here */
+  unsigned int otrust,otrust_min;
 
+  otrust = (get_ownertrust (pk) & TRUST_MASK);
+  otrust_min = get_min_ownertrust (pk);
+  if(otrust<otrust_min)
+    {
+      /* If the trust that the user has set is less than the trust
+        that was calculated from a trust signature chain, use the
+        higher of the two.  We do this here and not in
+        get_ownertrust since the underlying ownertrust should not
+        really be set - just the appearance of the ownertrust. */
 
+      otrust=otrust_min;
+    }
 
-    return rc;
+  return otrust;
 }
 
+/*
+ * Same as get_ownertrust but return a trust letter instead of an
+ * value.  This takes the minimum ownertrust value into account.
+ */
+int
+get_ownertrust_info (PKT_public_key *pk)
+{
+  return trust_letter(get_ownertrust_with_min(pk));
+}
 
+/*
+ * Same as get_ownertrust but return a trust string instead of an
+ * value.  This takes the minimum ownertrust value into account.
+ */
+const char *
+get_ownertrust_string (PKT_public_key *pk)
+{
+  return trust_value_to_string(get_ownertrust_with_min(pk));
+}
 
-
-/****************
- * stack is an array of (max_path+1) elements. If trust_seg_head is not
- * NULL it is a pointer to a variable which will receive a linked list
- * of trust paths - The caller has to free the memory.
+/*
+ * Set the trust value of the given public key to the new value.
+ * The key should be a primary one.
  */
-static int
-collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
-              TRUST_INFO *stack, TRUST_SEG_LIST *trust_seg_head )
+void
+update_ownertrust (PKT_public_key *pk, unsigned int new_trust )
 {
-    ulong rn, uidrn;
-    int marginal=0;
-    int fully=0;
-    LOCAL_ID_TABLE sigs_seen = NULL;
-
-    if( depth >= max_depth )  /* max cert_depth reached */
-       return TRUST_UNDEFINED;
-
-    stack[depth].lid = drec->r.dir.lid;
-    stack[depth].otrust = drec->r.dir.ownertrust;
-    stack[depth].trust = 0;
-    {  int i;
-
-       for(i=0; i < depth; i++ )
-           if( stack[i].lid == drec->r.dir.lid )
-               return TRUST_UNDEFINED; /* closed (we already visited this lid) */
-    }
-    if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) {
-       /* we are at the end of a path */
-       TRUST_SEG_LIST tsl;
-       int i;
-
-       stack[depth].trust = TRUST_ULTIMATE;
-       stack[depth].otrust = TRUST_ULTIMATE;
-       if( trust_seg_head ) {
-           /* we can now put copy our current stack to the trust_seg_list */
-           tsl = m_alloc( sizeof *tsl + (depth+1)*sizeof( TRUST_INFO ) );
-           for(i=0; i <= depth; i++ )
-               tsl->path[i] = stack[i];
-           tsl->pathlen = i;
-           tsl->next = *trust_seg_head;
-           *trust_seg_head = tsl;
-       }
-       return TRUST_ULTIMATE;
+  TRUSTREC rec;
+  int rc;
+  
+  rc = read_trust_record (pk, &rec);
+  if (!rc)
+    {
+      if (DBG_TRUST)
+        log_debug ("update ownertrust from %u to %u\n",
+                   (unsigned int)rec.r.trust.ownertrust, new_trust );
+      if (rec.r.trust.ownertrust != new_trust)
+        {
+          rec.r.trust.ownertrust = new_trust;
+          write_record( &rec );
+          revalidation_mark ();
+          do_sync ();
+        }
+    }
+  else if (rc == -1)
+    { /* no record yet - create a new one */
+      size_t dummy;
+
+      if (DBG_TRUST)
+        log_debug ("insert ownertrust %u\n", new_trust );
+
+      memset (&rec, 0, sizeof rec);
+      rec.recnum = tdbio_new_recnum ();
+      rec.rectype = RECTYPE_TRUST;
+      fingerprint_from_pk (pk, rec.r.trust.fingerprint, &dummy);
+      rec.r.trust.ownertrust = new_trust;
+      write_record (&rec);
+      revalidation_mark ();
+      do_sync ();
+      rc = 0;
+    }
+  else 
+    {
+      tdbio_invalid ();
     }
+}
 
-    /* loop over all user-ids */
-    if( !all )
-       sigs_seen = new_lid_table();
-    for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) {
-       TRUSTREC rec;  /* used for uids and sigs */
-       ulong sigrn;
-
-       read_record( rn, &rec, RECTYPE_UID );
-       uidrn = rec.r.uid.next;
-       if( !(rec.r.uid.uidflags & UIDF_CHECKED) )
-           continue; /* user id has not been checked */
-       if( !(rec.r.uid.uidflags & UIDF_VALID) )
-           continue; /* user id is not valid */
-       if( (rec.r.uid.uidflags & UIDF_REVOKED) )
-           continue; /* user id has been revoked */
-
-       /* loop over all signature records */
-       for( rn = rec.r.uid.siglist; rn; rn = sigrn ) {
-           int i;
-
-           read_record( rn, &rec, RECTYPE_SIG );
-           sigrn = rec.r.sig.next;
-
-           for(i=0; i < SIGS_PER_RECORD; i++ ) {
-               TRUSTREC tmp;
-               int ot, nt;
-               int unchecked = 0;
-
-               if( !rec.r.sig.sig[i].lid )
-                   continue; /* skip deleted sigs */
-               if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) ) {
-                   if( !all )
-                       continue; /* skip unchecked signatures */
-                   unchecked = 1;
-               }
-               else {
-                   if( !(rec.r.sig.sig[i].flag & SIGF_VALID) )
-                       continue; /* skip invalid signatures */
-                   if( (rec.r.sig.sig[i].flag & SIGF_EXPIRED) )
-                       continue; /* skip expired signatures */
-                   if( (rec.r.sig.sig[i].flag & SIGF_REVOKED) )
-                       continue; /* skip revoked signatures */
-               }
-
-               /* visit every signer only once (a signer may have
-                * signed more than one user ID) */
-               if( sigs_seen && ins_lid_table_item( sigs_seen,
-                                                    rec.r.sig.sig[i].lid, 0) )
-                   continue; /* we already have this one */
-
-               read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
-               if( tmp.rectype != RECTYPE_DIR ) {
-                   if( tmp.rectype != RECTYPE_SDIR )
-                       log_info("oops: lid %lu: sig %lu has rectype %d"
-                            " - skipped\n",
-                           drec->r.dir.lid, tmp.recnum, tmp.rectype );
-                   continue;
-               }
-               ot = tmp.r.dir.ownertrust & TRUST_MASK;
-               if( ot >= TRUST_FULLY )
-                   ot = TRUST_FULLY;  /* just in case */
-               nt = collect_paths( depth+1, max_depth, all, &tmp, stack,
-                                                       trust_seg_head );
-               nt &= TRUST_MASK;
-
-               if( nt < TRUST_MARGINAL || unchecked ) {
-                   continue;
-               }
-
-               if( nt == TRUST_ULTIMATE ) {
-                   /* we have signed this key and only in this special case
-                    * we assume that this one is fully trusted */
-                   if( !all ) {
-                       if( sigs_seen )
-                           release_lid_table( sigs_seen );
-                       return (stack[depth].trust = TRUST_FULLY);
-                   }
-               }
-
-               if( nt > ot )
-                   nt = ot;
-
-               if( nt >= TRUST_FULLY )
-                   fully++;
-               if( nt >= TRUST_MARGINAL )
-                   marginal++;
-
-               if( fully >= opt.completes_needed
-                   || marginal >= opt.marginals_needed ) {
-                   if( !all ) {
-                       if( sigs_seen )
-                           release_lid_table( sigs_seen );
-                       return (stack[depth].trust = TRUST_FULLY);
-                   }
-               }
-           }
-       }
-    }
-    if( sigs_seen )
-       release_lid_table( sigs_seen );
-    if( all && ( fully >= opt.completes_needed
-                || marginal >= opt.marginals_needed ) ) {
-       return (stack[depth].trust = TRUST_FULLY );
-    }
-    if( marginal ) {
-       return (stack[depth].trust = TRUST_MARGINAL);
+static void
+update_min_ownertrust (u32 *kid, unsigned int new_trust )
+{
+  PKT_public_key *pk;
+  TRUSTREC rec;
+  int rc;
+
+  pk = m_alloc_clear (sizeof *pk);
+  rc = get_pubkey (pk, kid);
+  if (rc)
+    {
+      log_error(_("public key %s not found: %s\n"),keystr(kid),g10_errstr(rc));
+      return;
+    }
+
+  rc = read_trust_record (pk, &rec);
+  if (!rc)
+    {
+      if (DBG_TRUST)
+        log_debug ("key %08lX%08lX: update min_ownertrust from %u to %u\n",
+                   (ulong)kid[0],(ulong)kid[1],
+                  (unsigned int)rec.r.trust.min_ownertrust,
+                  new_trust );
+      if (rec.r.trust.min_ownertrust != new_trust)
+        {
+          rec.r.trust.min_ownertrust = new_trust;
+          write_record( &rec );
+          revalidation_mark ();
+          do_sync ();
+        }
+    }
+  else if (rc == -1)
+    { /* no record yet - create a new one */
+      size_t dummy;
+
+      if (DBG_TRUST)
+        log_debug ("insert min_ownertrust %u\n", new_trust );
+
+      memset (&rec, 0, sizeof rec);
+      rec.recnum = tdbio_new_recnum ();
+      rec.rectype = RECTYPE_TRUST;
+      fingerprint_from_pk (pk, rec.r.trust.fingerprint, &dummy);
+      rec.r.trust.min_ownertrust = new_trust;
+      write_record (&rec);
+      revalidation_mark ();
+      do_sync ();
+      rc = 0;
+    }
+  else 
+    {
+      tdbio_invalid ();
     }
-    return (stack[depth].trust=TRUST_UNDEFINED);
 }
 
+/* Clear the ownertrust and min_ownertrust values.  Return true if a
+   change actually happened. */
+int
+clear_ownertrusts (PKT_public_key *pk)
+{
+  TRUSTREC rec;
+  int rc;
+  
+  rc = read_trust_record (pk, &rec);
+  if (!rc)
+    {
+      if (DBG_TRUST)
+       {
+         log_debug ("clearing ownertrust (old value %u)\n",
+                    (unsigned int)rec.r.trust.ownertrust);
+         log_debug ("clearing min_ownertrust (old value %u)\n",
+                    (unsigned int)rec.r.trust.min_ownertrust);
+       }
+      if (rec.r.trust.ownertrust || rec.r.trust.min_ownertrust)
+        {
+          rec.r.trust.ownertrust = 0;
+          rec.r.trust.min_ownertrust = 0;
+          write_record( &rec );
+          revalidation_mark ();
+          do_sync ();
+          return 1;
+        }
+    }
+  else if (rc != -1)
+    {
+      tdbio_invalid ();
+    }
+  return 0;
+}
 
-/****************
- * Given the directory record of a key, check whether we can
- * find a path to an ultimately trusted key.  We do this by
- * checking all key signatures up to a some depth.
+/* 
+ * Note: Caller has to do a sync 
  */
-static int
-verify_key( int max_depth, TRUSTREC *drec )
+static void
+update_validity (PKT_public_key *pk, PKT_user_id *uid,
+                 int depth, int validity)
 {
-    TRUST_INFO *tmppath = m_alloc_clear( (max_depth+1)* sizeof *tmppath );
-    int tr;
-
-    tr = collect_paths( 0, max_depth, 0, drec, tmppath, NULL );
-    m_free( tmppath );
-    return tr;
+  TRUSTREC trec, vrec;
+  int rc;
+  ulong recno;
+
+  namehash_from_uid(uid);
+
+  rc = read_trust_record (pk, &trec);
+  if (rc && rc != -1)
+    {
+      tdbio_invalid ();
+      return;
+    }
+  if (rc == -1) /* no record yet - create a new one */
+    { 
+      size_t dummy;
+
+      rc = 0;
+      memset (&trec, 0, sizeof trec);
+      trec.recnum = tdbio_new_recnum ();
+      trec.rectype = RECTYPE_TRUST;
+      fingerprint_from_pk (pk, trec.r.trust.fingerprint, &dummy);
+      trec.r.trust.ownertrust = 0;
+      }
+
+  /* locate an existing one */
+  recno = trec.r.trust.validlist;
+  while (recno)
+    {
+      read_record (recno, &vrec, RECTYPE_VALID);
+      if ( !memcmp (vrec.r.valid.namehash, uid->namehash, 20) )
+        break;
+      recno = vrec.r.valid.next;
+    }
+
+  if (!recno) /* insert a new validity record */
+    {
+      memset (&vrec, 0, sizeof vrec);
+      vrec.recnum = tdbio_new_recnum ();
+      vrec.rectype = RECTYPE_VALID;
+      memcpy (vrec.r.valid.namehash, uid->namehash, 20);
+      vrec.r.valid.next = trec.r.trust.validlist;
+      trec.r.trust.validlist = vrec.recnum;
+    }
+  vrec.r.valid.validity = validity;
+  vrec.r.valid.full_count = uid->help_full_count;
+  vrec.r.valid.marginal_count = uid->help_marginal_count;
+  write_record (&vrec);
+  trec.r.trust.depth = depth;
+  write_record (&trec);
 }
 
 
+/***********************************************
+ *********  Query trustdb values  **************
+ ***********************************************/
 
-
-/****************
- * we have the pubkey record and all needed informations are in the trustdb
- * but nothing more is known.
- */
-static int
-do_check( TRUSTREC *dr, unsigned *validity )
-{
-    if( !dr->r.dir.keylist ) {
-       log_error(_("Ooops, no keys\n"));
-       return G10ERR_TRUSTDB;
-    }
-    if( !dr->r.dir.uidlist ) {
-       log_error(_("Ooops, no user ids\n"));
-       return G10ERR_TRUSTDB;
-    }
-
-    if( tdbio_db_matches_options()
-       && (dr->r.dir.dirflags & DIRF_VALVALID)
-       && dr->r.dir.validity )
-       *validity = dr->r.dir.validity;
-    else {
-       *validity = verify_key( opt.max_cert_depth, dr );
-       if( (*validity & TRUST_MASK) >= TRUST_UNDEFINED
-           && tdbio_db_matches_options() ) {
-           /* update the cached validity value */
-           dr->r.dir.validity = (*validity & TRUST_MASK);
-           dr->r.dir.dirflags |= DIRF_VALVALID;
-           write_record( dr );
-       }
-    }
-
-    if( dr->r.dir.dirflags & DIRF_REVOKED )
-       *validity |= TRUST_FLAG_REVOKED;
-
-    return 0;
-}
-
-\f
-/****************
- * Perform some checks over the trustdb
- *  level 0: only open the db
- *       1: used for initial program startup
- */
-int
-init_trustdb( int level, const char *dbname )
-{
-    int rc=0;
-
-    if( !ultikey_table )
-       ultikey_table = new_lid_table();
-
-    if( !level || level==1 ) {
-       rc = tdbio_set_dbname( dbname, !!level );
-       if( rc )
-           return rc;
-       if( !level )
-           return 0;
-
-       /* verify that our own keys are in the trustDB
-        * or move them to the trustdb. */
-       rc = verify_own_keys();
-
-       /* should we check whether there is no other ultimately trusted
-        * key in the database? */
-
-    }
-    else
-       BUG();
-
-    return rc;
-}
-
+/* Return true if key is disabled */
+int
+cache_disabled_value(PKT_public_key *pk)
+{
+  int rc;
+  TRUSTREC trec;
+  int disabled=0;
+
+  if(pk->is_disabled)
+    return (pk->is_disabled==2);
+
+  init_trustdb();
+
+  rc = read_trust_record (pk, &trec);
+  if (rc && rc != -1)
+    {
+      tdbio_invalid ();
+      goto leave;
+    }
+  if (rc == -1) /* no record found, so assume not disabled */
+    goto leave;
+  if(trec.r.trust.ownertrust & TRUST_FLAG_DISABLED)
+    disabled=1;
+  /* Cache it for later so we don't need to look at the trustdb every
+     time */
+  if(disabled)
+    pk->is_disabled=2;
+  else
+    pk->is_disabled=1;
+
+ leave:
+   return disabled;
+}
 
 void
-list_trustdb( const char *username )
+check_trustdb_stale(void)
 {
-    TRUSTREC rec;
-
-    if( username && *username == '#' ) {
-       int rc;
-       ulong lid = atoi(username+1);
-
-       if( (rc = list_records( lid)) )
-           log_error(_("user '%s' read problem: %s\n"),
-                                           username, g10_errstr(rc));
-       else if( (rc = list_sigs( lid )) )
-           log_error(_("user '%s' list problem: %s\n"),
-                                           username, g10_errstr(rc));
-    }
-    else if( username ) {
-       PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-       int rc;
-
-       if( (rc = get_pubkey_byname( NULL, pk, username, NULL )) )
-           log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
-       else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
-           log_error(_("problem finding '%s' in trustdb: %s\n"),
-                                               username, g10_errstr(rc));
-       else if( rc == -1 )
-           log_error(_("user '%s' not in trustdb\n"), username);
-       else if( (rc = list_records( pk->local_id)) )
-           log_error(_("user '%s' read problem: %s\n"),
-                                               username, g10_errstr(rc));
-       else if( (rc = list_sigs( pk->local_id )) )
-           log_error(_("user '%s' list problem: %s\n"),
-                                               username, g10_errstr(rc));
-       free_public_key( pk );
-    }
-    else {
-       ulong recnum;
-       int i;
-
-       printf("TrustDB: %s\n", tdbio_get_dbname() );
-       for(i=9+strlen(tdbio_get_dbname()); i > 0; i-- )
-           putchar('-');
-       putchar('\n');
-       for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ )
-           tdbio_dump_record( &rec, stdout );
+  static int did_nextcheck=0;
+
+  init_trustdb ();
+  if (!did_nextcheck
+      && (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC))
+    {
+      ulong scheduled;
+
+      did_nextcheck = 1;
+      scheduled = tdbio_read_nextcheck ();
+      if (scheduled && scheduled <= make_timestamp ())
+        {
+          if (opt.no_auto_check_trustdb) 
+            {
+              pending_check_trustdb = 1;
+              log_info (_("please do a --check-trustdb\n"));
+            }
+          else
+            {
+              log_info (_("checking the trustdb\n"));
+              validate_keys (0);
+            }
+        }
     }
 }
 
-/****************
- * Print a list of all defined owner trust value.
+/*
+ * Return the validity information for PK.  If the namehash is not
+ * NULL, the validity of the corresponsing user ID is returned,
+ * otherwise, a reasonable value for the entire key is returned. 
  */
-void
-export_ownertrust()
+unsigned int
+get_validity (PKT_public_key *pk, PKT_user_id *uid)
 {
-    TRUSTREC rec;
-    TRUSTREC rec2;
-    ulong recnum;
-    int i;
-    byte *p;
-    int rc;
-
-    printf(_("# List of assigned trustvalues, created %s\n"
-            "# (Use \"gpgm --import-ownertrust\" to restore them)\n"),
-          asctimestamp( make_timestamp() ) );
-    for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
-       if( rec.rectype == RECTYPE_DIR ) {
-           if( !rec.r.dir.keylist ) {
-               log_error(_("directory record w/o primary key\n"));
-               continue;
-           }
-           if( !rec.r.dir.ownertrust )
-               continue;
-           rc = tdbio_read_record( rec.r.dir.keylist, &rec2, RECTYPE_KEY);
-           if( rc ) {
-               log_error(_("error reading key record: %s\n"), g10_errstr(rc));
-               continue;
+  TRUSTREC trec, vrec;
+  int rc;
+  ulong recno;
+  unsigned int validity;
+  u32 kid[2];
+  PKT_public_key *main_pk;
+
+  if(uid)
+    namehash_from_uid(uid);
+
+  init_trustdb ();
+  check_trustdb_stale();
+
+  keyid_from_pk (pk, kid);
+  if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1])
+    { /* this is a subkey - get the mainkey */
+      main_pk = m_alloc_clear (sizeof *main_pk);
+      rc = get_pubkey (main_pk, pk->main_keyid);
+      if (rc)
+        {
+         char *tempkeystr=m_strdup(keystr(pk->main_keyid));
+          log_error ("error getting main key %s of subkey %s: %s\n",
+                     tempkeystr, keystr(kid), g10_errstr(rc));
+         m_free(tempkeystr);
+          validity = TRUST_UNKNOWN; 
+          goto leave;
+       }
+    }
+  else
+    main_pk = pk;
+
+  if(opt.trust_model==TM_DIRECT)
+    {
+      /* Note that this happens BEFORE any user ID stuff is checked.
+        The direct trust model applies to keys as a whole. */
+      validity=get_ownertrust(main_pk);
+      goto leave;
+    }
+
+  rc = read_trust_record (main_pk, &trec);
+  if (rc && rc != -1)
+    {
+      tdbio_invalid ();
+      return 0;
+    }
+  if (rc == -1) /* no record found */
+    {
+      validity = TRUST_UNKNOWN; 
+      goto leave;
+    }
+
+  /* loop over all user IDs */
+  recno = trec.r.trust.validlist;
+  validity = 0;
+  while (recno)
+    {
+      read_record (recno, &vrec, RECTYPE_VALID);
+
+      if(uid)
+       {
+         /* If a user ID is given we return the validity for that
+            user ID ONLY.  If the namehash is not found, then there
+            is no validity at all (i.e. the user ID wasn't
+            signed). */
+         if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
+           {
+             validity=(vrec.r.valid.validity & TRUST_MASK);
+             break;
            }
-           p = rec2.r.key.fingerprint;
-           for(i=0; i < rec2.r.key.fingerprint_len; i++, p++ )
-               printf("%02X", *p );
-           printf(":%u:\n", (unsigned)rec.r.dir.ownertrust );
        }
-    }
+      else
+       {
+         /* If no namehash is given, we take the maximum validity
+            over all user IDs */
+         if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
+           validity = (vrec.r.valid.validity & TRUST_MASK);
+       }
+
+      recno = vrec.r.valid.next;
+    }
+  
+  if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
+    {
+      validity |= TRUST_FLAG_DISABLED;
+      pk->is_disabled=2;
+    }
+  else
+    pk->is_disabled=1;
+
+ leave:
+  /* set some flags direct from the key */
+  if (main_pk->is_revoked)
+    validity |= TRUST_FLAG_REVOKED;
+  if (main_pk != pk && pk->is_revoked)
+    validity |= TRUST_FLAG_SUB_REVOKED;
+  /* Note: expiration is a trust value and not a flag - don't know why
+   * I initially designed it that way */
+  if (main_pk->has_expired || pk->has_expired)
+    validity = (validity & ~TRUST_MASK) | TRUST_EXPIRED;
+  
+  if (pending_check_trustdb)
+    validity |= TRUST_FLAG_PENDING_CHECK;
+
+  if (main_pk != pk)
+    free_public_key (main_pk);
+  return validity;
 }
 
-
-void
-import_ownertrust( const char *fname )
+int
+get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
 {
-    FILE *fp;
-    int is_stdin=0;
-    char line[256];
-    char *p;
-    size_t n, fprlen;
-    unsigned otrust;
-
-    if( !fname || (*fname == '-' && !fname[1]) ) {
-       fp = stdin;
-       fname = "[stdin]";
-       is_stdin = 1;
-    }
-    else if( !(fp = fopen( fname, "r" )) ) {
-       log_error_f(fname, _("can't open file: %s\n"), strerror(errno) );
-       return;
-    }
-
-    while( fgets( line, DIM(line)-1, fp ) ) {
-       TRUSTREC rec;
-       int rc;
+    int trustlevel;
 
-       if( !*line || *line == '#' )
-           continue;
-       n = strlen(line);
-       if( line[n-1] != '\n' ) {
-           log_error_f(fname, _("line too long\n") );
-           /* ... or last line does not have a LF */
-           break; /* can't continue */
-       }
-       for(p = line; *p && *p != ':' ; p++ )
-           if( !isxdigit(*p) )
-               break;
-       if( *p != ':' ) {
-           log_error_f(fname, _("error: missing colon\n") );
-           continue;
-       }
-       fprlen = p - line;
-       if( fprlen != 32 && fprlen != 40 ) {
-           log_error_f(fname, _("error: invalid fingerprint\n") );
-           continue;
-       }
-       if( sscanf(p, ":%u:", &otrust ) != 1 ) {
-           log_error_f(fname, _("error: no ownertrust value\n") );
-           continue;
-       }
-       if( !otrust )
-           continue; /* no otrust defined - no need to update or insert */
-       /* convert the ascii fingerprint to binary */
-       for(p=line, fprlen=0; *p != ':'; p += 2 )
-           line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
-       line[fprlen] = 0;
-
-      repeat:
-       rc = tdbio_search_dir_byfpr( line, fprlen, 0, &rec );
-       if( !rc ) { /* found: update */
-           if( rec.r.dir.ownertrust )
-               log_info("LID %lu: changing trust from %u to %u\n",
-                         rec.r.dir.lid, rec.r.dir.ownertrust, otrust );
-           else
-               log_info("LID %lu: setting trust to %u\n",
-                                  rec.r.dir.lid, otrust );
-           rec.r.dir.ownertrust = otrust;
-           write_record( &rec );
-       }
-       else if( rc == -1 ) { /* not found; get the key from the ring */
-           PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-
-           log_info_f(fname, _("key not in trustdb, searching ring.\n"));
-           rc = get_pubkey_byfprint( pk, line, fprlen );
-           if( rc )
-               log_info_f(fname, _("key not in ring: %s\n"), g10_errstr(rc));
-           else {
-               rc = query_trust_record( pk );  /* only as assertion */
-               if( rc != -1 )
-                   log_error_f(fname, _("Oops: key is now in trustdb???\n"));
-               else {
-                   rc = insert_trust_record( pk );
-                   if( !rc )
-                       goto repeat; /* update the ownertrust */
-                   log_error_f(fname, _("insert trust record failed: %s\n"),
-                                                          g10_errstr(rc) );
-               }
-           }
-       }
-       else /* error */
-           log_error_f(fname, _("error finding dir record: %s\n"),
-                                                   g10_errstr(rc));
-    }
-    if( ferror(fp) )
-       log_error_f(fname, _("read error: %s\n"), strerror(errno) );
-    if( !is_stdin )
-       fclose(fp);
-    do_sync();
+    trustlevel = get_validity (pk, uid);
+    if( trustlevel & TRUST_FLAG_REVOKED )
+       return 'r';
+    return trust_letter ( trustlevel );
 }
 
-
-
-
-static void
-print_path( int pathlen, TRUST_INFO *path, FILE *fp, ulong highlight )
+const char *
+get_validity_string (PKT_public_key *pk, PKT_user_id *uid)
 {
-    int rc, c, i;
-    u32 keyid[2];
-    char *p;
-    size_t n;
-
-    for( i = 0; i < pathlen; i++ )  {
-       if( highlight )
-           fputs(highlight == path[i].lid? "* ":"  ", fp );
-       rc = keyid_from_lid( path[i].lid, keyid );
-       if( rc )
-           fprintf(fp, "????????.%lu:", path[i].lid );
-       else
-           fprintf(fp,"%08lX.%lu:", (ulong)keyid[1], path[i].lid );
-       c = trust_letter(path[i].otrust);
-       if( c )
-           putc( c, fp );
-       else
-           fprintf( fp, "%02x", path[i].otrust );
-       putc('/', fp);
-       c = trust_letter(path[i].trust);
-       if( c )
-           putc( c, fp );
-       else
-           fprintf( fp, "%02x", path[i].trust );
-       putc(' ', fp);
-       p = get_user_id( keyid, &n );
-       putc(' ', fp);
-       putc('\"', fp);
-       print_string( fp, p, n > 40? 40:n, 0 );
-       putc('\"', fp);
-       m_free(p);
-       putc('\n', fp );
-    }
-}
+  int trustlevel;
 
-
-static int
-cmp_tsl_array( const void *xa, const void *xb )
-{
-    TRUST_SEG_LIST a = *(TRUST_SEG_LIST*)xa;
-    TRUST_SEG_LIST b = *(TRUST_SEG_LIST*)xb;
-    return a->pathlen - b->pathlen;
+  trustlevel = get_validity (pk, uid);
+  if( trustlevel & TRUST_FLAG_REVOKED )
+    return _("revoked");
+  return trust_value_to_string(trustlevel);
 }
 
-
 static void
-sort_tsl_list( TRUST_SEG_LIST *trust_seg_list )
+get_validity_counts (PKT_public_key *pk, PKT_user_id *uid)
 {
-    TRUST_SEG_LIST *array, *tail, tsl;
-    size_t n;
-
-    for(n=0, tsl = *trust_seg_list; tsl; tsl = tsl->next )
-       n++;
-    array = m_alloc( (n+1) * sizeof *array );
-    for(n=0, tsl = *trust_seg_list; tsl; tsl = tsl->next )
-       array[n++] = tsl;
-    array[n] = NULL;
-    qsort( array, n, sizeof *array, cmp_tsl_array );
-    *trust_seg_list = NULL;
-    tail = trust_seg_list;
-    for(n=0; (tsl=array[n]); n++ ) {
-       *tail = tsl;
-       tail = &tsl->next;
-    }
-    m_free( array );
-}
+  TRUSTREC trec, vrec;
+  ulong recno;
 
+  if(pk==NULL || uid==NULL)
+    BUG();
 
-void
-list_trust_path( const char *username )
-{
-    int rc;
-    TRUSTREC rec;
-    TRUST_INFO *tmppath;
-    TRUST_SEG_LIST trust_seg_list, tsl, tsl2;
-    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-
-    if( (rc = get_pubkey_byname(NULL, pk, username, NULL )) )
-       log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
-    else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
-       log_error(_("problem finding '%s' in trustdb: %s\n"),
-                                           username, g10_errstr(rc));
-    else if( rc == -1 ) {
-       log_info(_("user '%s' not in trustdb - inserting\n"), username);
-       rc = insert_trust_record( pk );
-       if( rc )
-           log_error(_("failed to put '%s' into trustdb: %s\n"),
-                                                   username, g10_errstr(rc));
-       else {
-           assert( pk->local_id );
-       }
-    }
-    free_public_key( pk );
-
-    /* collect the paths */
-    tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
-    trust_seg_list = NULL;
-    collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &trust_seg_list );
-    m_free( tmppath );
-    sort_tsl_list( &trust_seg_list );
-    /* and now print them */
-    for(tsl = trust_seg_list; tsl; tsl = tsl->next ) {
-       print_path( tsl->pathlen, tsl->path, stdout, 0 );
-       if( tsl->next )
-           putchar('\n');
-    }
+  namehash_from_uid(uid);
 
-    /* release the list */
-    for(tsl = trust_seg_list; tsl; tsl = tsl2 ) {
-       tsl2 = tsl->next;
-       m_free( tsl );
-    }
-    trust_seg_list = NULL;
-}
+  uid->help_marginal_count=uid->help_full_count=0;
 
+  init_trustdb ();
 
-/****************
- * Check the complete trustdb or only the entries for the given username.
- * We check the complete database. If a username is given or the special
- * username "*" is used, a complete recheck is done.  With no user ID
- * only the records which are not yet checkd are now checked.
- */
-void
-check_trustdb( const char *username )
-{
-    TRUSTREC rec;
-    KBNODE keyblock = NULL;
-    KBPOS kbpos;
-    int rc;
-    int recheck = username && *username == '*' && !username[1];
-
-    if( username && !recheck ) {
-       rc = find_keyblock_byname( &kbpos, username );
-       if( !rc )
-           rc = read_keyblock( &kbpos, &keyblock );
-       if( rc ) {
-           log_error(_("%s: keyblock read problem: %s\n"),
-                                   username, g10_errstr(rc));
-       }
-       else {
-           int modified;
-
-           rc = update_trust_record( keyblock, 1, &modified );
-           if( rc == -1 ) { /* not yet in trustdb: insert */
-               rc = insert_trust_record(
-                           find_kbnode( keyblock, PKT_PUBLIC_KEY
-                                      ) ->pkt->pkt.public_key );
+  if(read_trust_record (pk, &trec)!=0)
+    return;
 
-           }
-           if( rc )
-               log_error(_("%s: update failed: %s\n"),
-                                          username, g10_errstr(rc) );
-           else if( modified )
-               log_info(_("%s: updated\n"), username );
-           else
-               log_info(_("%s: okay\n"), username );
+  /* loop over all user IDs */
+  recno = trec.r.trust.validlist;
+  while (recno)
+    {
+      read_record (recno, &vrec, RECTYPE_VALID);
 
+      if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
+       {
+         uid->help_marginal_count=vrec.r.valid.marginal_count;
+         uid->help_full_count=vrec.r.valid.full_count;
+         /*  printf("Fetched marginal %d, full %d\n",uid->help_marginal_count,uid->help_full_count); */
+         break;
        }
-       release_kbnode( keyblock ); keyblock = NULL;
-    }
-    else {
-       ulong recnum;
-       ulong count=0, upd_count=0, err_count=0, skip_count=0;
-
-       for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
-           if( rec.rectype == RECTYPE_DIR ) {
-               TRUSTREC tmp;
-               int modified;
-
-               if( !rec.r.dir.keylist ) {
-                   log_info(_("lid %lu: dir record w/o key - skipped\n"),
-                                                                 recnum);
-                   count++;
-                   skip_count++;
-                   continue;
-               }
 
-               read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY );
-
-               rc = get_keyblock_byfprint( &keyblock,
-                                           tmp.r.key.fingerprint,
-                                           tmp.r.key.fingerprint_len );
-               if( rc ) {
-                   log_error(_("lid %lu: keyblock not found: %s\n"),
-                                                recnum, g10_errstr(rc) );
-                   count++;
-                   skip_count++;
-                   continue;
-               }
-
-               rc = update_trust_record( keyblock, recheck, &modified );
-               if( rc ) {
-                   log_error(_("lid %lu: update failed: %s\n"),
-                                                recnum, g10_errstr(rc) );
-                   err_count++;
-               }
-               else if( modified ) {
-                   if( opt.verbose )
-                       log_info(_("lid %lu: updated\n"), recnum );
-                   upd_count++;
-               }
-               else if( opt.verbose > 1 )
-                   log_info(_("lid %lu: okay\n"), recnum );
-
-               release_kbnode( keyblock ); keyblock = NULL;
-               if( !(++count % 100) )
-                   log_info(_("%lu keys so far processed\n"), count);
-           }
-       }
-       log_info(_("%lu keys processed\n"), count);
-       if( skip_count )
-           log_info(_("\t%lu keys skipped\n"), skip_count);
-       if( err_count )
-           log_info(_("\t%lu keys with errors\n"), err_count);
-       if( upd_count )
-           log_info(_("\t%lu keys updated\n"), upd_count);
+      recno = vrec.r.valid.next;
     }
 }
 
-
-/****************
- * Put new entries  from the pubrings into the trustdb.
- * This function honors the sig flags to speed up the check.
- */
 void
-update_trustdb( )
-{
-    KBNODE keyblock = NULL;
-    KBPOS kbpos;
-    int rc;
-
-    rc = enum_keyblocks( 0, &kbpos, &keyblock );
-    if( !rc ) {
-       ulong count=0, upd_count=0, err_count=0, new_count=0;
-
-       while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
-           int modified;
-
-           rc = update_trust_record( keyblock, 1, &modified );
-           if( rc == -1 ) { /* not yet in trustdb: insert */
-               PKT_public_key *pk =
-                           find_kbnode( keyblock, PKT_PUBLIC_KEY
-                                      ) ->pkt->pkt.public_key;
-               rc = insert_trust_record( pk );
-               if( rc && !pk->local_id ) {
-                   log_error(_("lid ?: insert failed: %s\n"),
-                                                    g10_errstr(rc) );
-                   err_count++;
-               }
-               else if( rc ) {
-                   log_error(_("lid %lu: insert failed: %s\n"),
-                                      pk->local_id, g10_errstr(rc) );
-                   err_count++;
-               }
-               else {
-                   if( opt.verbose )
-                       log_info(_("lid %lu: inserted\n"), pk->local_id );
-                   new_count++;
-               }
-           }
-           else if( rc ) {
-               log_error(_("lid %lu: update failed: %s\n"),
-                        lid_from_keyblock(keyblock), g10_errstr(rc) );
-               err_count++;
-           }
-           else if( modified ) {
-               if( opt.verbose )
-                   log_info(_("lid %lu: updated\n"), lid_from_keyblock(keyblock));
-               upd_count++;
-           }
-           else if( opt.verbose > 1 )
-               log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) );
-
-           release_kbnode( keyblock ); keyblock = NULL;
-           if( !(++count % 100) )
-               log_info(_("%lu keys so far processed\n"), count);
-       }
-       log_info(_("%lu keys processed\n"), count);
-       if( err_count )
-           log_info(_("\t%lu keys with errors\n"), err_count);
-       if( upd_count )
-           log_info(_("\t%lu keys updated\n"), upd_count);
-       if( new_count )
-           log_info(_("\t%lu keys inserted\n"), new_count);
-    }
-    if( rc && rc != -1 )
-       log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
-
-    enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
-    release_kbnode( keyblock );
-}
-
-
-\f
-/****************
- * Get the trustlevel for this PK.
- * Note: This does not ask any questions
- * Returns: 0 okay of an errorcode
- *
- * It operates this way:
- *  locate the pk in the trustdb
- *     found:
- *         Do we have a valid cache record for it?
- *             yes: return trustlevel from cache
- *             no:  make a cache record and all the other stuff
- *     not found:
- *         try to insert the pubkey into the trustdb and check again
- *
- * Problems: How do we get the complete keyblock to check that the
- *          cache record is actually valid?  Think we need a clever
- *          cache in getkey.c  to keep track of this stuff. Maybe it
- *          is not necessary to check this if we use a local pubring. Hmmmm.
- */
-int
-check_trust( PKT_public_key *pk, unsigned *r_trustlevel )
-{
-    TRUSTREC rec;
-    unsigned trustlevel = TRUST_UNKNOWN;
-    int rc=0;
-    u32 cur_time;
-    u32 keyid[2];
-
-
-    keyid_from_pk( pk, keyid );
-
-    /* get the pubkey record */
-    if( pk->local_id ) {
-       read_record( pk->local_id, &rec, RECTYPE_DIR );
-    }
-    else { /* no local_id: scan the trustdb */
-       if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 ) {
-           log_error(_("check_trust: search dir record failed: %s\n"),
-                                                           g10_errstr(rc));
-           return rc;
-       }
-       else if( rc == -1 ) { /* not found - insert */
-           rc = insert_trust_record( pk );
-           if( rc ) {
-               log_error(_("key %08lX: insert trust record failed: %s\n"),
-                                         (ulong)keyid[1], g10_errstr(rc));
-               goto leave;
-           }
-           log_info(_("key %08lX.%lu: inserted into trustdb\n"),
-                                         (ulong)keyid[1], pk->local_id );
-           /* and re-read the dir record */
-           read_record( pk->local_id, &rec, RECTYPE_DIR );
-       }
-    }
-    cur_time = make_timestamp();
-    if( pk->timestamp > cur_time ) {
-       log_info(_("key %08lX.%lu: created in future "
-                  "(time warp or clock problem)\n"),
-                                         (ulong)keyid[1], pk->local_id );
-       return G10ERR_TIME_CONFLICT;
-    }
-
-    if( pk->expiredate && pk->expiredate <= cur_time ) {
-       log_info(_("key %08lX.%lu: expired at %s\n"),
-                       (ulong)keyid[1], pk->local_id,
-                            asctimestamp( pk->expiredate) );
-        trustlevel = TRUST_EXPIRED;
-    }
-    else {
-       rc = do_check( &rec, &trustlevel );
-       if( rc ) {
-           log_error(_("key %08lX.%lu: trust check failed: %s\n"),
-                           (ulong)keyid[1], pk->local_id, g10_errstr(rc));
-           return rc;
-       }
-    }
-
-
-  leave:
-    if( DBG_TRUST )
-       log_debug("check_trust() returns trustlevel %04x.\n", trustlevel);
-    *r_trustlevel = trustlevel;
-    return 0;
-}
-
-
-
-
-int
-query_trust_info( PKT_public_key *pk )
+list_trust_path( const char *username )
 {
-    unsigned trustlevel;
-    int c;
-
-    if( check_trust( pk, &trustlevel ) )
-       return '?';
-    if( trustlevel & TRUST_FLAG_REVOKED )
-       return 'r';
-    c = trust_letter( (trustlevel & TRUST_MASK) );
-    if( !c )
-       c = '?';
-    return c;
 }
 
-
-
 /****************
  * Enumerate all keys, which are needed to build all trust paths for
  * the given key.  This function does not return the key itself or
 enum_cert_paths( void **context, ulong *lid,
                 unsigned *ownertrust, unsigned *validity )
 {
-    struct enum_cert_paths_ctx *ctx;
-    TRUST_SEG_LIST tsl;
-
-    if( !lid ) {  /* release the context */
-       if( *context ) {
-           TRUST_SEG_LIST tsl2;
-
-           ctx = *context;
-           for(tsl = ctx->tsl_head; tsl; tsl = tsl2 ) {
-               tsl2 = tsl->next;
-               m_free( tsl );
-           }
-           *context = NULL;
-       }
-       return -1;
-    }
-
-    if( !*context ) {
-       TRUST_INFO *tmppath;
-       TRUSTREC rec;
-
-       if( !*lid )
-           return -1;
-
-       ctx = m_alloc_clear( sizeof *ctx );
-       *context = ctx;
-       /* collect the paths */
-       read_record( *lid, &rec, RECTYPE_DIR );
-       tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
-       tsl = NULL;
-       collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &tsl );
-       m_free( tmppath );
-       sort_tsl_list( &tsl );
-       /* setup the context */
-       ctx->tsl_head = tsl;
-       ctx->tsl = ctx->tsl_head;
-       ctx->idx = 0;
-    }
-    else
-       ctx = *context;
-
-    while( ctx->tsl && ctx->idx >= ctx->tsl->pathlen ) {
-       ctx->tsl = ctx->tsl->next;
-       ctx->idx = 0;
-    }
-    tsl = ctx->tsl;
-    if( !tsl )
-       return -1; /* eof */
-
-    if( ownertrust )
-       *ownertrust = tsl->path[ctx->idx].otrust;
-    if( validity )
-       *validity = tsl->path[ctx->idx].trust;
-    *lid = tsl->path[ctx->idx].lid;
-    ctx->idx++;
-    return ctx->idx-1;
+    return -1;
 }
 
 
 /****************
  * Print the current path
  */
-int
+void
 enum_cert_paths_print( void **context, FILE *fp,
                                       int refresh, ulong selected_lid )
 {
-    struct enum_cert_paths_ctx *ctx;
-    TRUST_SEG_LIST tsl;
-
-    if( !*context )
-       return;
-    ctx = *context;
-    if( !ctx->tsl )
-       return;
-    tsl = ctx->tsl;
-
-    if( !fp )
-       fp = stderr;
-
-    if( refresh ) { /* update the ownertrust and if possible the validity */
-       int i;
-       int match = tdbio_db_matches_options();
-
-       for( i = 0; i < tsl->pathlen; i++ )  {
-           TRUSTREC rec;
-
-           read_record( tsl->path[i].lid, &rec, RECTYPE_DIR );
-           tsl->path[i].otrust = rec.r.dir.ownertrust;
-           /* update validity only if we have it in the cache
-            * calculation is too time consuming */
-           if( match && (rec.r.dir.dirflags & DIRF_VALVALID)
-                     && rec.r.dir.validity ) {
-               tsl->path[i].trust = rec.r.dir.validity;
-               if( rec.r.dir.dirflags & DIRF_REVOKED )
-                   tsl->path[i].trust = TRUST_FLAG_REVOKED;
-           }
-       }
-    }
-
-    print_path( tsl->pathlen, tsl->path, fp, selected_lid );
-}
-
-
-/****************
- * Return the assigned ownertrust value for the given LID
- */
-unsigned
-get_ownertrust( ulong lid )
-{
-    TRUSTREC rec;
-
-    read_record( lid, &rec, RECTYPE_DIR );
-    return rec.r.dir.ownertrust;
-}
-
-int
-get_ownertrust_info( ulong lid )
-{
-    unsigned otrust;
-    int c;
-
-    otrust = get_ownertrust( lid );
-    c = trust_letter( (otrust & TRUST_MASK) );
-    if( !c )
-       c = '?';
-    return c;
-}
-
-/*
- * Return an allocated buffer with the preference values for
- * the key with LID and the userid which is identified by the
- * HAMEHASH or the firstone if namehash is NULL.  ret_n receives
- * the length of the allcoated buffer. Structure of the buffer is
- * a repeated sequences of 2 bytes; where the first byte describes the
- * type of the preference and the second one the value.  The constants
- * PREFTYPE_xxxx should be used to reference a type.
- */
-byte *
-get_pref_data( ulong lid, const byte *namehash, size_t *ret_n )
-{
-    TRUSTREC rec;
-    ulong recno;
-
-    read_record( lid, &rec, RECTYPE_DIR );
-    for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
-       read_record( recno, &rec, RECTYPE_UID );
-       if( rec.r.uid.prefrec
-           && ( !namehash || !memcmp(namehash, rec.r.uid.namehash, 20) ))  {
-           byte *buf;
-           /* found the correct one or the first one */
-           read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
-           if( rec.r.pref.next )
-               log_info(_("WARNING: can't yet handle long pref records\n"));
-           buf = m_alloc( ITEMS_PER_PREF_RECORD );
-           memcpy( buf, rec.r.pref.data, ITEMS_PER_PREF_RECORD );
-           *ret_n = ITEMS_PER_PREF_RECORD;
-           return buf;
-       }
-    }
-    return NULL;
+    return;
 }
 
 
-
-/****************
- * Check whether the algorithm is in one of the pref records
- */
-int
-is_algo_in_prefs( ulong lid, int preftype, int algo )
-{
-    TRUSTREC rec;
-    ulong recno;
-    int i;
-    byte *pref;
-
-    read_record( lid, &rec, RECTYPE_DIR );
-    for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
-       read_record( recno, &rec, RECTYPE_UID );
-       if( rec.r.uid.prefrec ) {
-           read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
-           if( rec.r.pref.next )
-               log_info(_("WARNING: can't yet handle long pref records\n"));
-           pref = rec.r.pref.data;
-           for(i=0; i+1 < ITEMS_PER_PREF_RECORD; i+=2 ) {
-               if( pref[i] == preftype && pref[i+1] == algo )
-                   return 1;
-           }
-       }
-    }
-    return 0;
-}
-
+\f
+/****************************************
+ *********** NEW NEW NEW ****************
+ ****************************************/
 
 static int
-get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
+ask_ownertrust (u32 *kid,int minimum)
 {
-    int rc=0;
-
-    if( pk->local_id ) {
-       read_record( pk->local_id, rec, RECTYPE_DIR );
-    }
-    else { /* no local_id: scan the trustdb */
-       if( (rc=tdbio_search_dir_bypk( pk, rec )) && rc != -1 )
-           log_error(_("get_dir_record: search_record failed: %s\n"),
-                                                           g10_errstr(rc));
-    }
-    return rc;
+  PKT_public_key *pk;
+  int rc;
+  int ot;
+
+  pk = m_alloc_clear (sizeof *pk);
+  rc = get_pubkey (pk, kid);
+  if (rc)
+    {
+      log_error (_("public key %s not found: %s\n"),
+                 keystr(kid), g10_errstr(rc) );
+      return TRUST_UNKNOWN;
+    }
+  if(opt.force_ownertrust)
+    {
+      log_info("force trust for key %s to %s\n",
+              keystr(kid),trust_value_to_string(opt.force_ownertrust));
+      update_ownertrust(pk,opt.force_ownertrust);
+      ot=opt.force_ownertrust;
+    }
+  else
+    {
+      ot=edit_ownertrust(pk,0);
+      if(ot>0)
+       ot = get_ownertrust (pk);
+      else if(ot==0)
+       ot = minimum?minimum:TRUST_UNDEFINED;
+      else
+       ot = -1; /* quit */
+    }
+
+  free_public_key( pk );
+
+  return ot;
 }
 
 
-
-/****************
- * This function simply looks for the key in the trustdb
- * and makes sure that pk->local_id is set to the correct value.
- * Return: 0 = found
- *        -1 = not found
- *       other = error
- */
-int
-query_trust_record( PKT_public_key *pk )
-{
-    TRUSTREC rec;
-    return get_dir_record( pk, &rec );
-}
-
-
-int
-clear_trust_checked_flag( PKT_public_key *pk )
+static void
+mark_keyblock_seen (KeyHashTable tbl, KBNODE node)
 {
-    TRUSTREC rec;
-    int rc;
-
-    rc = get_dir_record( pk, &rec );
-    if( rc )
-       return rc;
-
-    /* check whether they are already reset */
-    if(   !(rec.r.dir.dirflags & DIRF_CHECKED)
-       && !(rec.r.dir.dirflags & DIRF_VALVALID) )
-       return 0;
-
-    /* reset the flag */
-    rec.r.dir.dirflags &= ~DIRF_CHECKED;
-    rec.r.dir.dirflags &= ~DIRF_VALVALID;
-    write_record( &rec );
-    do_sync();
-    return 0;
+  for ( ;node; node = node->next )
+    if (node->pkt->pkttype == PKT_PUBLIC_KEY
+       || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+      {
+        u32 aki[2];
+
+        keyid_from_pk (node->pkt->pkt.public_key, aki);
+        add_key_hash_table (tbl, aki);
+      }
 }
 
 
-
-
 static void
-check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
-               TRUSTREC *sigrec, int sigidx, ulong hint_owner )
+dump_key_array (int depth, struct key_array *keys)
 {
-    KBNODE node;
-    int rc, state;
-    byte uhash[20];
-    int is_selfsig;
-    PKT_signature *sigpkt = NULL;
-    TRUSTREC tmp;
-    u32 sigkid[2];
-    int revoke = 0;
-
-    if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED )
-       log_info(_("NOTE: sig rec %lu[%d] in hintlist "
-                  "of %lu but marked as checked\n"),
-                   sigrec->recnum, sigidx, hint_owner );
-    if( !(sigrec->r.sig.sig[sigidx].flag & SIGF_NOPUBKEY) )
-       log_info(_("NOTE: sig rec %lu[%d] in hintlist "
-                  "of %lu but not marked\n"),
-                   sigrec->recnum, sigidx, hint_owner );
-
-    read_record( sigrec->r.sig.sig[sigidx].lid, &tmp, 0 );
-    if( tmp.rectype != RECTYPE_DIR ) {
-       /* we need the dir record */
-       log_error(_("sig rec %lu[%d] in hintlist "
-                   "of %lu does not point to a dir record\n"),
-                   sigrec->recnum, sigidx, hint_owner );
-       return;
-    }
-    if( !tmp.r.dir.keylist ) {
-       log_error(_("lid %lu: no primary key\n"), tmp.r.dir.lid );
-       return;
-    }
-    read_record(tmp.r.dir.keylist, &tmp, RECTYPE_KEY );
-    keyid_from_fingerprint( tmp.r.key.fingerprint,
-                           tmp.r.key.fingerprint_len, sigkid );
-
-
-    /* find the correct signature packet */
-    state = 0;
-    for( node=keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_USER_ID ) {
-           PKT_user_id *uidpkt = node->pkt->pkt.user_id;
-
-           if( state )
-               break;
-           rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
-           if( !memcmp( uhash, uidrec_hash, 20 ) )
-               state = 1;
-       }
-       else if( state && node->pkt->pkttype == PKT_SIGNATURE ) {
-           sigpkt = node->pkt->pkt.signature;
-           if( sigpkt->keyid[0] == sigkid[0]
-               && sigpkt->keyid[1] == sigkid[1]
-               && ( (sigpkt->sig_class&~3) == 0x10
-                    || ( revoke = (sigpkt->sig_class == 0x30)) ) ) {
-               state = 2;
-               break; /* found */
-           }
-       }
-    }
-
-    if( !node ) {
-       log_info(_("lid %lu: user id not found in keyblock\n"), lid );
-       return ;
-    }
-    if( state != 2 ) {
-       log_info(_("lid %lu: user id without signature\n"), lid );
-       return ;
-    }
+  struct key_array *kar;
+
+  for (kar=keys; kar->keyblock; kar++)
+    {
+      KBNODE node = kar->keyblock;
+      u32 kid[2];
+
+      keyid_from_pk(node->pkt->pkt.public_key, kid);
+      printf ("%d:%08lX%08lX:K::%c::::\n",
+              depth, (ulong)kid[0], (ulong)kid[1], '?');
+
+      for (; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_USER_ID)
+            {
+              int len = node->pkt->pkt.user_id->len;
+
+              if (len > 30)
+                len = 30;
+              printf ("%d:%08lX%08lX:U:::%c:::",
+                      depth, (ulong)kid[0], (ulong)kid[1],
+                      (node->flag & 4)? 'f':
+                      (node->flag & 2)? 'm':
+                      (node->flag & 1)? 'q':'-');
+              print_string (stdout,  node->pkt->pkt.user_id->name, len, ':');
+              putchar (':');
+              putchar ('\n');
+            }
+        }
+    }
+}  
 
-    /* and check the sig */
-    rc = check_key_signature( keyblock, node, &is_selfsig );
-    if( is_selfsig ) {
-       log_error(_("lid %lu: self-signature in hintlist\n"), lid );
-       return;
-    }
-
-    /* FiXME: handling fo SIGF_REVOKED is not correct! */
-
-    if( !rc ) { /* valid signature */
-       if( opt.verbose )
-           log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-                   (ulong)keyid[1], lid, uhash[18], uhash[19],
-                   (ulong)sigpkt->keyid[1],
-                   revoke? _("Valid certificate revocation")
-                         : _("Good certificate") );
-       sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
-       if( revoke )
-           sigrec->r.sig.sig[sigidx].flag |= SIGF_REVOKED;
-    }
-    else if( rc == G10ERR_NO_PUBKEY ) {
-       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-             (ulong)keyid[1], lid, uhash[18], uhash[19],
-              (ulong)sigpkt->keyid[1],
-                _("very strange: no public key\n") );
-       sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY;
-    }
-    else {
-       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-                   (ulong)keyid[1], lid, uhash[18], uhash[19],
-                   (ulong)sigpkt->keyid[1], g10_errstr(rc) );
-       sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED;
-    }
-    sigrec->dirty = 1;
-}
 
-
-/****************
- * Process a hintlist.
- * Fixme: this list is not anymore anchored to another
- *       record, so it should be put elsewehere in case of an error
- */
 static void
-process_hintlist( ulong hintlist, ulong hint_owner )
+store_validation_status (int depth, KBNODE keyblock, KeyHashTable stored)
 {
-    ulong hlst_rn;
-    int rc;
-
-    for( hlst_rn = hintlist; hlst_rn; ) {
-       TRUSTREC hlstrec;
-       int hlst_idx;
-
-       read_record( hlst_rn, &hlstrec, RECTYPE_HLST );
-
-       for( hlst_idx=0; hlst_idx < ITEMS_PER_HLST_RECORD; hlst_idx++ ) {
-           TRUSTREC dirrec;
-           TRUSTREC uidrec;
-           TRUSTREC tmprec;
-           KBNODE keyblock = NULL;
-           u32 keyid[2];
-           ulong lid;
-           ulong r1, r2;
-
-           lid = hlstrec.r.hlst.rnum[hlst_idx];
-           if( !lid )
-               continue;
-
-           read_record( lid, &dirrec, 0 );
-           /* make sure it points to a dir record:
-            * this should be true because it only makes sense to
-            * call this function if the dir record is available */
-           if( dirrec.rectype != RECTYPE_DIR )  {
-               log_error(_("hintlist %lu[%d] of %lu "
-                           "does not point to a dir record\n"),
-                           hlst_rn, hlst_idx, hint_owner );
-               continue;
-           }
-           if( !dirrec.r.dir.keylist ) {
-               log_error(_("lid %lu does not have a key\n"), lid );
-               continue;
-           }
-
-           /* get the keyblock */
-           read_record( dirrec.r.dir.keylist, &tmprec, RECTYPE_KEY );
-           rc = get_keyblock_byfprint( &keyblock,
-                                       tmprec.r.key.fingerprint,
-                                       tmprec.r.key.fingerprint_len );
-           if( rc ) {
-               log_error(_("lid %lu: can't get keyblock: %s\n"),
-                                                   lid, g10_errstr(rc) );
-               continue;
-           }
-           keyid_from_fingerprint( tmprec.r.key.fingerprint,
-                                   tmprec.r.key.fingerprint_len, keyid );
-
-           /* Walk over all user ids and their signatures and check all
-            * the signature which are created by hint_owner */
-           for( r1 = dirrec.r.dir.uidlist; r1; r1 = uidrec.r.uid.next ) {
-               TRUSTREC sigrec;
-
-               read_record( r1, &uidrec, RECTYPE_UID );
-               for( r2 = uidrec.r.uid.siglist; r2; r2 = sigrec.r.sig.next ) {
-                   int i;
-
-                   read_record( r2, &sigrec, RECTYPE_SIG );
-                   sigrec.dirty = 0;
-                   for(i=0; i < SIGS_PER_RECORD; i++ ) {
-                       if( !sigrec.r.sig.sig[i].lid )
-                           continue; /* skip deleted sigs */
-                       if( sigrec.r.sig.sig[i].lid != hint_owner )
-                           continue; /* not for us */
-                       /* some diagnostic messages */
-                       /* and do the signature check */
-                       check_hint_sig( lid, keyblock, keyid,
-                                       uidrec.r.uid.namehash,
-                                       &sigrec, i, hint_owner );
-                   }
-                   if( sigrec.dirty )
-                       write_record( &sigrec );
-               }
-           }
-           release_kbnode( keyblock );
-       } /* loop over hlst entries */
-
-       /* delete this hlst record */
-       hlst_rn = hlstrec.r.hlst.next;
-       delete_record( hlstrec.recnum );
-    } /* loop over hintlist */
-}
-
+  KBNODE node;
+  int status;
+  int any = 0;
+
+  for (node=keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_USER_ID)
+        {
+          PKT_user_id *uid = node->pkt->pkt.user_id;
+          if (node->flag & 4)
+            status = TRUST_FULLY;
+          else if (node->flag & 2)
+            status = TRUST_MARGINAL;
+          else if (node->flag & 1)
+            status = TRUST_UNDEFINED;
+          else
+            status = 0;
+          
+          if (status)
+            {
+              update_validity (keyblock->pkt->pkt.public_key,
+                              uid, depth, status);
+
+             mark_keyblock_seen(stored,keyblock);
+
+              any = 1;
+            }
+        }
+    }
+
+  if (any)
+    do_sync ();
+}  
 
-/****************
- * Create or update shadow dir record and return the LID of the record
+/*
+ * check whether the signature sig is in the klist k
  */
-static ulong
-create_shadow_dir( PKT_signature *sig, ulong lid  )
+static struct key_item *
+is_in_klist (struct key_item *k, PKT_signature *sig)
 {
-    TRUSTREC sdir, hlst, tmphlst;
-    ulong recno, newlid;
-    int tmpidx=0; /* avoids gcc warnign - this is controlled by tmphlst */
-    int rc;
-
-    /* first see whether we already have such a record */
-    rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir );
-    if( rc && rc != -1 ) {
-       log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
-       die_invalid_db();
-    }
-    if( rc == -1 ) { /* not found: create */
-       memset( &sdir, 0, sizeof sdir );
-       sdir.recnum = tdbio_new_recnum();
-       sdir.rectype= RECTYPE_SDIR;
-       sdir.r.sdir.lid = sdir.recnum;
-       sdir.r.sdir.keyid[0] = sig->keyid[0];
-       sdir.r.sdir.keyid[1] = sig->keyid[1];
-       sdir.r.sdir.pubkey_algo = sig->pubkey_algo;
-       sdir.r.sdir.hintlist = 0;
-       write_record( &sdir );
-    }
-    newlid = sdir.recnum;
-    /* Put the record number into the hintlist.
-     * (It is easier to use the lid and not the record number of the
-     * key to save some space (assuming that a signator has
-     * signed more than one user id - and it is easier to implement.)
-     */
-    tmphlst.recnum = 0;
-    for( recno=sdir.r.sdir.hintlist; recno; recno = hlst.r.hlst.next) {
-       int i;
-       read_record( recno, &hlst, RECTYPE_HLST );
-       for( i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
-           if( !hlst.r.hlst.rnum[i] ) {
-               if( !tmphlst.recnum ) {
-                   tmphlst = hlst;
-                   tmpidx = i;
-               }
-           }
-           else if( hlst.r.hlst.rnum[i] == lid )
-               return newlid; /* the signature is already in the hintlist */
-       }
-    }
-    /* not yet in the hint list, write it */
-    if( tmphlst.recnum ) { /* we have an empty slot */
-       tmphlst.r.hlst.rnum[tmpidx] = lid;
-       write_record( &tmphlst );
-    }
-    else { /* must append a new hlst record */
-       memset( &hlst, 0, sizeof hlst );
-       hlst.recnum = tdbio_new_recnum();
-       hlst.rectype = RECTYPE_HLST;
-       hlst.r.hlst.next = sdir.r.sdir.hintlist;
-       hlst.r.hlst.rnum[0] = lid;
-       write_record( &hlst );
-       sdir.r.sdir.hintlist = hlst.recnum;
-       write_record( &sdir );
+  for (; k; k = k->next)
+    {
+      if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1])
+        return k;
     }
-
-    return newlid;
+  return NULL;
 }
 
-
-/****************
- * This function checks the given public key and inserts or updates
- * the keyrecord from the trustdb.  Revocation certificates
- * are handled here and the keybinding of subkeys is checked.
- * Hmmm: Should we check here, that the key has at least one valid
- * user ID or do we allow keys w/o user ID?
- *
- * keyblock points to the first node in the keyblock,
- * keynode is the node with the public key to check
- * (either primary or secondary), keyid is the keyid of
- * the primary key, drec is the directory record and recno_list
- * is a list used to keep track of visited records.
- * Existing keyflags are recalculated if recheck is true.
+/*
+ * Mark the signature of the given UID which are used to certify it.
+ * To do this, we first revmove all signatures which are not valid and
+ * from the remain ones we look for the latest one.  If this is not a
+ * certification revocation signature we mark the signature by setting
+ * node flag bit 8.  Note that flag bits 9 and 10 are used for internal
+ * purposes.  
  */
 static void
-upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
-               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
+mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
+                       u32 *main_kid, struct key_item *klist,
+                       u32 curtime, u32 *next_expire)
 {
-    TRUSTREC krec;
-    KBNODE  node;
-    PKT_public_key *pk = keynode->pkt->pkt.public_key;
-    ulong lid = drec->recnum;
-    byte fpr[MAX_FINGERPRINT_LEN];
-    size_t fprlen;
-    ulong recno, newrecno;
-    int keybind_seen = 0;
-    int revoke_seen = 0;
-    int rc;
-
-    fingerprint_from_pk( pk, fpr, &fprlen );
-    /* do we already have this key? */
-    for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) {
-       read_record( recno, &krec, RECTYPE_KEY );
-       if( krec.r.key.fingerprint_len == fprlen
-           && !memcmp( krec.r.key.fingerprint, fpr, fprlen ) )
-           break;
-    }
-    if( recno ) { /* yes */
-       ins_recno_list( recno_list, recno, RECTYPE_KEY );
-    }
-    else { /* no: insert this new key */
-       recheck = 1;
-       memset( &krec, 0, sizeof(krec) );
-       krec.rectype = RECTYPE_KEY;
-       krec.r.key.lid = lid;
-       krec.r.key.pubkey_algo = pk->pubkey_algo;
-       krec.r.key.fingerprint_len = fprlen;
-       memcpy(krec.r.key.fingerprint, fpr, fprlen );
-       krec.recnum = newrecno = tdbio_new_recnum();
-       write_record( &krec );
-       ins_recno_list( recno_list, newrecno, RECTYPE_KEY );
-       /* and put this new record at the end of the keylist */
-       if( !(recno=drec->r.dir.keylist) ) {
-           /* this is the first key */
-           drec->r.dir.keylist = newrecno;
-           drec->dirty = 1;
-       }
-       else { /* we already have a key, append the new one */
-           TRUSTREC save = krec;
-           for( ; recno; recno = krec.r.key.next )
-               read_record( recno, &krec, RECTYPE_KEY );
-           krec.r.key.next = newrecno;
-           write_record( &krec );
-           krec = save;
-       }
-    }
-
-    if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) )
-       return;
-
-    /* check keybindings and revocations */
-    krec.r.key.keyflags = 0;
-    if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) {
-       /* we assume that a primary key is always valid
-        * and check later whether we have a revocation */
-       krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
-    }
-
-    for( node=keynode->next; node; node = node->next ) {
-       PKT_signature *sig;
-
-       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           break; /* ready */
-       else if( node->pkt->pkttype != PKT_SIGNATURE )
+  KBNODE node;
+  PKT_signature *sig;
+  
+  /* first check all signatures */
+  for (node=uidnode->next; node; node = node->next)
+    {
+      node->flag &= ~(1<<8 | 1<<9 | 1<<10);
+      if (node->pkt->pkttype == PKT_USER_ID
+          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        break; /* ready */
+      if (node->pkt->pkttype != PKT_SIGNATURE)
+        continue;
+      
+      sig = node->pkt->pkt.signature;
+      if (sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
+        continue; /* ignore self-signatures */
+      if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
+        continue; /* we only look at these signature classes */
+      if(sig->sig_class>=0x11 && sig->sig_class<=0x13 &&
+        sig->sig_class-0x10<opt.min_cert_level)
+       continue;
+      if (!is_in_klist (klist, sig))
+        continue;  /* no need to check it then */
+      if (check_key_signature (keyblock, node, NULL))
+        continue; /* ignore invalid signatures */
+      node->flag |= 1<<9;
+    }      
+  /* reset the remaining flags */
+  for (; node; node = node->next)
+      node->flag &= ~(1<<8 | 1<<9 | 1 << 10);
+
+  /* kbnode flag usage: bit 9 is here set for signatures to consider,
+   * bit 10 will be set by the loop to keep track of keyIDs already
+   * processed, bit 8 will be set for the usable signatures */
+
+  /* for each cert figure out the latest valid one */
+  for (node=uidnode->next; node; node = node->next)
+    {
+      KBNODE n, signode;
+      u32 kid[2];
+      u32 sigdate;
+      
+      if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        break;
+      if ( !(node->flag & (1<<9)) )
+        continue; /* not a node to look at */
+      if ( (node->flag & (1<<10)) )
+        continue; /* signature with a keyID already processed */
+      node->flag |= (1<<10); /* mark this node as processed */
+      sig = node->pkt->pkt.signature;
+      signode = node;
+      sigdate = sig->timestamp;
+      kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
+      for (n=uidnode->next; n; n = n->next)
+        {
+          if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+            break;
+          if ( !(n->flag & (1<<9)) )
+            continue;
+          if ( (n->flag & (1<<10)) )
+            continue; /* shortcut already processed signatures */
+          sig = n->pkt->pkt.signature;
+          if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
+            continue;
+          n->flag |= (1<<10); /* mark this node as processed */
+
+         /* If signode is nonrevocable and unexpired and n isn't,
+             then take signode (skip).  It doesn't matter which is
+             older: if signode was older then we don't want to take n
+             as signode is nonrevocable.  If n was older then we're
+             automatically fine. */
+         
+         if(((IS_UID_SIG(signode->pkt->pkt.signature) &&
+              !signode->pkt->pkt.signature->flags.revocable &&
+              (signode->pkt->pkt.signature->expiredate==0 ||
+               signode->pkt->pkt.signature->expiredate>curtime))) &&
+            (!(IS_UID_SIG(n->pkt->pkt.signature) &&
+               !n->pkt->pkt.signature->flags.revocable &&
+               (n->pkt->pkt.signature->expiredate==0 ||
+                n->pkt->pkt.signature->expiredate>curtime))))
            continue;
 
-       sig = node->pkt->pkt.signature;
-
-       if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
-           continue; /* not a self signature */
-       if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
-           if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
-               continue; /* oops, not for a main key */
-           /* we check until we find a valid keybinding */
-           rc = check_key_signature( keyblock, node, NULL );
-           if( !rc ) {
-               if( opt.verbose )
-                   log_info(_(
-                       "key %08lX.%lu: Good subkey binding\n"),
-                        (ulong)keyid_from_pk(pk,NULL), lid );
-               krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
-           }
-           else {
-               log_info(_(
-                 "key %08lX.%lu: Invalid subkey binding: %s\n"),
-                   (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
-               krec.r.key.keyflags |= KEYF_CHECKED;
-               krec.r.key.keyflags &= ~KEYF_VALID;
-           }
-           keybind_seen = 1;
-       }
-       else if( sig->sig_class == 0x20 && !revoke_seen ) {
-           if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-               continue; /* a subkey is not expected here */
-           /* This is a key revocation certificate: check it */
-           rc = check_key_signature( keyblock, node, NULL );
-           if( !rc ) {
-               if( opt.verbose )
-                   log_info(_(
-                       "key %08lX.%lu: Valid key revocation\n"),
-                        (ulong)keyid_from_pk(pk,NULL), lid );
-               krec.r.key.keyflags |= KEYF_REVOKED;
-           }
-           else {
-               log_info(_(
-                 "key %08lX.%lu: Invalid key revocation: %s\n"),
-                 (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
-           }
-           revoke_seen = 1;
-       }
-       else if( sig->sig_class == 0x28 && !revoke_seen ) {
-           if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
-               continue; /* a mainkey is not expected here */
-           /* This is a subkey revocation certificate: check it */
-           /* fixme: we should also check the revocation
-            * is newer than the key (OpenPGP) */
-           rc = check_key_signature( keyblock, node, NULL );
-           if( !rc ) {
-               if( opt.verbose )
-                   log_info(_(
-                       "key %08lX.%lu: Valid subkey revocation\n"),
-                        (ulong)keyid_from_pk(pk,NULL), lid );
-               krec.r.key.keyflags |= KEYF_REVOKED;
-           }
-           else {
-               log_info(_(
-                 "key %08lX.%lu: Invalid subkey binding: %s\n"),
-                 (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
-           }
-           revoke_seen = 1;
-       }
+         /* If n is nonrevocable and unexpired and signode isn't,
+             then take n.  Again, it doesn't matter which is older: if
+             n was older then we don't want to take signode as n is
+             nonrevocable.  If signode was older then we're
+             automatically fine. */
+         
+         if((!(IS_UID_SIG(signode->pkt->pkt.signature) &&
+               !signode->pkt->pkt.signature->flags.revocable &&
+               (signode->pkt->pkt.signature->expiredate==0 ||
+                signode->pkt->pkt.signature->expiredate>curtime))) &&
+            ((IS_UID_SIG(n->pkt->pkt.signature) &&
+              !n->pkt->pkt.signature->flags.revocable &&
+              (n->pkt->pkt.signature->expiredate==0 ||
+               n->pkt->pkt.signature->expiredate>curtime))))
+            {
+              signode = n;
+              sigdate = sig->timestamp;
+             continue;
+            }
+
+         /* At this point, if it's newer, it goes in as the only
+             remaining possibilities are signode and n are both either
+             revocable or expired or both nonrevocable and unexpired.
+             If the timestamps are equal take the later ordered
+             packet, presuming that the key packets are hopefully in
+             their original order. */
+
+          if (sig->timestamp >= sigdate)
+            {
+              signode = n;
+              sigdate = sig->timestamp;
+            }
+        }
+      sig = signode->pkt->pkt.signature;
+      if (IS_UID_SIG (sig))
+        { /* this seems to be a usable one which is not revoked. 
+           * Just need to check whether there is an expiration time,
+           * We do the expired certification after finding a suitable
+           * certification, the assumption is that a signator does not
+           * want that after the expiration of his certificate the
+           * system falls back to an older certification which has a
+           * different expiration time */
+          const byte *p;
+          u32 expire;
+                    
+          p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
+          expire = p? sig->timestamp + buffer_to_u32(p) : 0;
+
+          if (expire==0 || expire > curtime )
+            {
+              signode->flag |= (1<<8); /* yeah, found a good cert */
+              if (expire && expire < *next_expire)
+                *next_expire = expire;
+            }
+        }
     }
-
-    write_record( &krec );
 }
 
-
-/****************
- * This function checks the given user ID and inserts or updates
- * the uid record of the trustdb.  Revocation certificates
- * are handled here.
- *
- * keyblock points to the first node in the keyblock,
- * uidnode is the node with the user id to check
- * keyid is the keyid of
- * the primary key, drec is the directory record and recno_list
- * is a list used to keep track of visited records.
- * Existing uidflags are recalculated if recheck is true.
- */
-static void
-upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
-               TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
+/* Used by validate_one_keyblock to confirm a regexp within a trust
+   signature.  Returns 1 for match, and 0 for no match or regex
+   error. */
+static int
+check_regexp(const char *expr,const char *string)
 {
-    ulong lid = drec->recnum;
-    PKT_user_id *uid = uidnode->pkt->pkt.user_id;
-    TRUSTREC urec;
-    PKT_signature *selfsig = NULL;
-    byte uidhash[20];
-    KBNODE node;
-    ulong recno, newrecno;
-    int rc;
-
-    /* see whether we already have an uid record */
-    rmd160_hash_buffer( uidhash, uid->name, uid->len );
-    for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
-       read_record( recno, &urec, RECTYPE_UID );
-       if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) )
-           break;
-    }
-    if( recno ) { /* we already have this record */
-       ins_recno_list( recno_list, recno, RECTYPE_UID );
-    }
-    else { /* new user id */
-       recheck = 1;
-       memset( &urec, 0 , sizeof(urec) );
-       urec.rectype = RECTYPE_UID;
-       urec.r.uid.lid = drec->recnum;
-       memcpy(urec.r.uid.namehash, uidhash, 20 );
-       urec.recnum = newrecno = tdbio_new_recnum();
-       write_record( &urec );
-       ins_recno_list( recno_list, newrecno, RECTYPE_UID );
-       /* and put this new record at the end of the uidlist */
-       if( !(recno=drec->r.dir.uidlist) ) { /* this is the first uid */
-           drec->r.dir.uidlist = newrecno;
-           drec->dirty = 1;
-       }
-       else { /* we already have an uid, append it to the list */
-           TRUSTREC save = urec;
-           for( ; recno; recno = urec.r.key.next )
-               read_record( recno, &urec, RECTYPE_UID );
-           urec.r.uid.next = newrecno;
-           write_record( &urec );
-           urec = save;
-       }
-    }
-
-    if( recheck || !(urec.r.uid.uidflags & UIDF_CHECKED) ) {
-       /* check self signatures */
-       urec.r.uid.uidflags = 0;
-       for( node=uidnode->next; node; node = node->next ) {
-           PKT_signature *sig;
-
-           if( node->pkt->pkttype == PKT_USER_ID )
-               break; /* ready */
-           if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-               break; /* ready */
-           if( node->pkt->pkttype != PKT_SIGNATURE )
-               continue;
-
-           sig = node->pkt->pkt.signature;
-
-           if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
-               continue; /* not a self signature */
-
-           if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
-               rc = check_key_signature( keyblock, node, NULL );
-               if( !rc ) {
-                   if( opt.verbose )
-                       log_info( "uid %08lX.%lu/%02X%02X: %s\n",
-                          (ulong)keyid[1], lid, uidhash[18], uidhash[19],
-                                 _("Good self-signature") );
-                   urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
-                   if( !selfsig )
-                       selfsig = sig; /* use the first valid sig */
-                   else if( sig->timestamp > selfsig->timestamp
-                            && sig->sig_class >= selfsig->sig_class )
-                       selfsig = sig; /* but this one is newer */
-               }
-               else {
-                   log_info( "uid %08lX/%02X%02X: %s: %s\n",
-                              (ulong)keyid[1], uidhash[18], uidhash[19],
-                             _("Invalid self-signature"),
-                              g10_errstr(rc) );
-                   urec.r.uid.uidflags |= UIDF_CHECKED;
-               }
-           }
-           else if( sig->sig_class == 0x30 ) { /* cert revocation */
-               rc = check_key_signature( keyblock, node, NULL );
-               if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) {
-                   log_info( "uid %08lX.%lu/%02X%02X: %s\n",
-                          (ulong)keyid[1], lid, uidhash[18], uidhash[19],
-                          _("Valid user ID revocation skipped "
-                            "due to a newer self signature\n") );
-               }
-               else if( !rc ) {
-                   if( opt.verbose )
-                       log_info( "uid %08lX.%lu/%02X%02X: %s\n",
-                          (ulong)keyid[1], lid, uidhash[18], uidhash[19],
-                                _("Valid user ID revocation\n") );
-                   urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
-                   urec.r.uid.uidflags |= UIDF_REVOKED;
-               }
-               else {
-                   log_info("uid %08lX/%02X%02X: %s: %s\n",
-                               (ulong)keyid[1], uidhash[18], uidhash[19],
-                              _("Invalid user ID revocation"),
-                                                       g10_errstr(rc) );
-               }
-           }
-       }
-       write_record( &urec );
-    } /* end check self-signatures */
-
-
-    if( (urec.r.uid.uidflags & (UIDF_CHECKED|UIDF_VALID))
-       != (UIDF_CHECKED|UIDF_VALID) )
-       return; /* user ID is not valid, so no need to check more things */
-
-    /* check the preferences */
-    if( selfsig )
-       upd_pref_record( &urec, keyid, selfsig );
-
-    /* check non-self signatures */
-    for( node=uidnode->next; node; node = node->next ) {
-       PKT_signature *sig;
-
-       if( node->pkt->pkttype == PKT_USER_ID )
-           break; /* ready */
-       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           break; /* ready */
-       if( node->pkt->pkttype != PKT_SIGNATURE )
-           continue;
+#ifdef DISABLE_REGEX
+  /* When DISABLE_REGEX is defined, assume all regexps do not
+     match. */
+  return 0;
+#elif defined(__riscos__)
+  return riscos_check_regexp(expr, string, DBG_TRUST);
+#else
+  int ret;
+  regex_t pat;
+
+  if(regcomp(&pat,expr,REG_ICASE|REG_NOSUB|REG_EXTENDED)!=0)
+    return 0;
 
-       sig = node->pkt->pkt.signature;
+  ret=regexec(&pat,string,0,NULL,0);
 
-       if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] )
-           continue; /* skip self signature */
+  regfree(&pat);
 
-       if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
-           upd_cert_record( keyblock, node, keyid, drec, recno_list,
-                            recheck, &urec, uidhash, 0 );
-       }
-       else if( sig->sig_class == 0x30 ) { /* cert revocation */
-           upd_cert_record( keyblock, node, keyid, drec, recno_list,
-                            recheck, &urec, uidhash, 1 );
-       }
-    } /* end check certificates */
+  if(DBG_TRUST)
+    log_debug("regexp `%s' on `%s': %s\n",expr,string,ret==0?"YES":"NO");
 
-    write_record( &urec );
+  return (ret==0);
+#endif
 }
 
-
-
-/****************
- *
- *
+/*
+ * Return true if the key is signed by one of the keys in the given
+ * key ID list.  User IDs with a valid signature are marked by node
+ * flags as follows:
+ *  flag bit 0: There is at least one signature
+ *           1: There is marginal confidence that this is a legitimate uid
+ *           2: There is full confidence that this is a legitimate uid.
+ *           8: Used for internal purposes.
+ *           9: Ditto (in mark_usable_uid_certs())
+ *          10: Ditto (ditto)
+ * This function assumes that all kbnode flags are cleared on entry.
  */
-static void
-upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
+static int
+validate_one_keyblock (KBNODE kb, struct key_item *klist,
+                       u32 curtime, u32 *next_expire)
 {
-    static struct {
-       sigsubpkttype_t subpkttype;
-       int preftype;
-    } ptable[] = {
-       { SIGSUBPKT_PREF_SYM,   PREFTYPE_SYM    },
-       { SIGSUBPKT_PREF_HASH,  PREFTYPE_HASH   },
-       { SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR  },
-       { 0, 0 }
-    };
-    TRUSTREC prec;
-    ulong lid = urec->r.uid.lid ;
-    const byte *uidhash = urec->r.uid.namehash;
-    const byte *s;
-    size_t n;
-    int k, i;
-    ulong recno;
-    byte prefs_sig[200];
-    int n_prefs_sig = 0;
-    byte prefs_rec[200];
-    int n_prefs_rec = 0;
-
-    /* check for changed preferences */
-    for(k=0; ptable[k].subpkttype; k++ ) {
-       s = parse_sig_subpkt2( sig, ptable[k].subpkttype, &n );
-       if( s ) {
-           for( ; n; n--, s++ ) {
-               if( n_prefs_sig >= DIM(prefs_sig)-1 ) {
-                   log_info("uid %08lX.%lu/%02X%02X: %s\n",
-                             (ulong)keyid[1], lid, uidhash[18], uidhash[19],
-                             _("Too many preferences") );
-                   break;
+  struct key_item *kr;
+  KBNODE node, uidnode=NULL;
+  PKT_user_id *uid=NULL;
+  PKT_public_key *pk = kb->pkt->pkt.public_key;
+  u32 main_kid[2];
+  int issigned=0, any_signed = 0;
+
+  keyid_from_pk(pk, main_kid);
+  for (node=kb; node; node = node->next)
+    {
+      /* A bit of discussion here: is it better for the web of trust
+        to be built among only self-signed uids?  On the one hand, a
+        self-signed uid is a statement that the key owner definitely
+        intended that uid to be there, but on the other hand, a
+        signed (but not self-signed) uid does carry trust, of a sort,
+        even if it is a statement being made by people other than the
+        key owner "through" the uids on the key owner's key.  I'm
+        going with the latter.  However, if the user ID was
+        explicitly revoked, or passively allowed to expire, that
+        should stop validity through the user ID until it is
+        resigned.  -dshaw */
+
+      if (node->pkt->pkttype == PKT_USER_ID
+         && !node->pkt->pkt.user_id->is_revoked
+         && !node->pkt->pkt.user_id->is_expired)
+        {
+          if (uidnode && issigned)
+            {
+              if (uid->help_full_count >= opt.completes_needed
+                  || uid->help_marginal_count >= opt.marginals_needed )
+                uidnode->flag |= 4; 
+              else if (uid->help_full_count || uid->help_marginal_count)
+                uidnode->flag |= 2;
+              uidnode->flag |= 1;
+              any_signed = 1;
+            }
+          uidnode = node;
+         uid=uidnode->pkt->pkt.user_id;
+
+         /* If the selfsig is going to expire... */
+         if(uid->expiredate && uid->expiredate<*next_expire)
+           *next_expire = uid->expiredate;
+
+          issigned = 0;
+         get_validity_counts(pk,uid);
+          mark_usable_uid_certs (kb, uidnode, main_kid, klist, 
+                                 curtime, next_expire);
+        }
+      else if (node->pkt->pkttype == PKT_SIGNATURE
+              && (node->flag & (1<<8)) && uid)
+        {
+         /* Note that we are only seeing unrevoked sigs here */
+          PKT_signature *sig = node->pkt->pkt.signature;
+          
+          kr = is_in_klist (klist, sig);
+         /* If the trust_regexp does not match, it's as if the sig
+             did not exist.  This is safe for non-trust sigs as well
+             since we don't accept a regexp on the sig unless it's a
+             trust sig. */
+          if (kr && (kr->trust_regexp==NULL || opt.trust_model!=TM_PGP ||
+                    (uidnode && check_regexp(kr->trust_regexp,
+                                           uidnode->pkt->pkt.user_id->name))))
+            {
+             if(DBG_TRUST && opt.trust_model==TM_PGP && sig->trust_depth)
+               log_debug("trust sig on %s, sig depth is %d, kr depth is %d\n",
+                         uidnode->pkt->pkt.user_id->name,sig->trust_depth,
+                         kr->trust_depth);
+
+             /* Are we part of a trust sig chain?  We always favor
+                 the latest trust sig, rather than the greater or
+                 lesser trust sig or value.  I could make a decent
+                 argument for any of these cases, but this seems to be
+                 what PGP does, and I'd like to be compatible. -dms */
+             if(opt.trust_model==TM_PGP && sig->trust_depth
+                && pk->trust_timestamp<=sig->timestamp
+                && (sig->trust_depth<=kr->trust_depth
+                    || kr->ownertrust==TRUST_ULTIMATE))
+               {
+                 /* If we got here, we know that:
+
+                    this is a trust sig.
+
+                    it's a newer trust sig than any previous trust
+                    sig on this key (not uid).
+
+                    it is legal in that it was either generated by an
+                    ultimate key, or a key that was part of a trust
+                    chain, and the depth does not violate the
+                    original trust sig.
+
+                    if there is a regexp attached, it matched
+                    successfully.
+                 */
+
+                 if(DBG_TRUST)
+                   log_debug("replacing trust value %d with %d and "
+                             "depth %d with %d\n",
+                             pk->trust_value,sig->trust_value,
+                             pk->trust_depth,sig->trust_depth);
+
+                 pk->trust_value=sig->trust_value;
+                 pk->trust_depth=sig->trust_depth-1;
+
+                 /* If the trust sig contains a regexp, record it
+                    on the pk for the next round. */
+                 if(sig->trust_regexp)
+                   pk->trust_regexp=sig->trust_regexp;
                }
-               prefs_sig[n_prefs_sig++] = ptable[k].preftype;
-               prefs_sig[n_prefs_sig++] = *s;
-           }
-       }
-    }
-    for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
-       read_record( recno, &prec, RECTYPE_PREF );
-       for(i = 0; i < ITEMS_PER_PREF_RECORD; i +=2 )  {
-           if( n_prefs_rec >= DIM(prefs_rec)-1 ) {
-               log_info("uid %08lX.%lu/%02X%02X: %s\n",
-                         (ulong)keyid[1], lid, uidhash[18], uidhash[19],
-                         _("Too many preference items") );
-               break;
-           }
-           if( prec.r.pref.data[i] ) {
-               prefs_rec[n_prefs_rec++] = prec.r.pref.data[i];
-               prefs_rec[n_prefs_rec++] = prec.r.pref.data[i+1];
+
+              if (kr->ownertrust == TRUST_ULTIMATE)
+                uid->help_full_count = opt.completes_needed;
+              else if (kr->ownertrust == TRUST_FULLY)
+                uid->help_full_count++;
+              else if (kr->ownertrust == TRUST_MARGINAL)
+                uid->help_marginal_count++;
+              issigned = 1;
            }
-       }
-    }
-    if( n_prefs_sig == n_prefs_rec
-       && !memcmp( prefs_sig, prefs_rec, n_prefs_sig ) )
-       return;  /* not changed */
-
-    /* Preferences have changed:  Delete all pref records
-     * This is much simpler than checking whether we have to
-     * do update the record at all - the record cache may care about it
-     */
-    for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
-       read_record( recno, &prec, RECTYPE_PREF );
-       delete_record( recno );
+        }
     }
 
-    if( n_prefs_sig > ITEMS_PER_PREF_RECORD )
-        log_info(_("WARNING: can't yet handle long pref records\n"));
-
-    memset( &prec, 0, sizeof prec );
-    prec.recnum = tdbio_new_recnum();
-    prec.rectype = RECTYPE_PREF;
-    prec.r.pref.lid = lid;
-    if( n_prefs_sig <= ITEMS_PER_PREF_RECORD )
-       memcpy( prec.r.pref.data, prefs_sig, n_prefs_sig );
-    else { /* need more than one pref record */
-       TRUSTREC tmp;
-       ulong nextrn;
-       int n = n_prefs_sig;
-       byte *pp = prefs_sig;
-
-       memcpy( prec.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
-       n -= ITEMS_PER_PREF_RECORD;
-       pp += ITEMS_PER_PREF_RECORD;
-       nextrn = prec.r.pref.next = tdbio_new_recnum();
-       do {
-           memset( &tmp, 0, sizeof tmp );
-           tmp.recnum = nextrn;
-           tmp.rectype = RECTYPE_PREF;
-           tmp.r.pref.lid = lid;
-           if( n <= ITEMS_PER_PREF_RECORD ) {
-               memcpy( tmp.r.pref.data, pp, n );
-               n = 0;
-           }
-           else {
-               memcpy( tmp.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
-               n -= ITEMS_PER_PREF_RECORD;
-               pp += ITEMS_PER_PREF_RECORD;
-               nextrn = tmp.r.pref.next = tdbio_new_recnum();
-           }
-           write_record( &tmp );
-       } while( n );
+  if (uidnode && issigned)
+    {
+      if (uid->help_full_count >= opt.completes_needed
+         || uid->help_marginal_count >= opt.marginals_needed )
+        uidnode->flag |= 4; 
+      else if (uid->help_full_count || uid->help_marginal_count)
+        uidnode->flag |= 2;
+      uidnode->flag |= 1;
+      any_signed = 1;
     }
-    write_record( &prec );
-    urec->r.uid.prefrec = prec.recnum;
-    urec->dirty = 1;
-}
 
+  return any_signed;
+}
 
 
-static void
-upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
-                TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
-                TRUSTREC *urec, const byte *uidhash, int revoke )
+static int
+search_skipfnc (void *opaque, u32 *kid, PKT_user_id *dummy)
 {
-    /* We simply insert the signature into the sig records but
-     * avoid duplicate ones.  We do not check them here because
-     * there is a big chance, that we import required public keys
-     * later.  The problem with this is that we must somewhere store
-     * the information about this signature (we need a record id).
-     * We do this by using the record type shadow dir, which will
-     * be converted to a dir record as soon as a new public key is
-     * inserted into the trustdb.
-     */
-    ulong lid = drec->recnum;
-    PKT_signature *sig = signode->pkt->pkt.signature;
-    TRUSTREC rec;
-    ulong recno;
-    TRUSTREC delrec;
-    int delrecidx=0;
-    int newflag = 0;
-    ulong newlid = 0;
-    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
-    ulong pk_lid = 0;
-    int found_sig = 0;
-    int found_delrec = 0;
-    int rc;
-
-    delrec.recnum = 0;
-
-    /* get the LID of the pubkey of the signature under verification */
-    rc = get_pubkey( pk, sig->keyid );
-    if( !rc ) {
-       if( pk->local_id )
-           pk_lid = pk->local_id;
-       else {
-           rc = tdbio_search_dir_bypk( pk, &rec );
-           if( !rc )
-               pk_lid = rec.recnum;
-           else if( rc == -1 ) { /* see whether there is a sdir instead */
-               u32 akid[2];
-
-               keyid_from_pk( pk, akid );
-               rc = tdbio_search_sdir( akid, pk->pubkey_algo, &rec );
-               if( !rc )
-                   pk_lid = rec.recnum;
-           }
-       }
-    }
-    free_public_key( pk ); pk = NULL;
-
-    /* Loop over all signatures just in case one is not correctly
-     * marked. If we see the correct signature, set a flag.
-     * delete duplicate signatures (should not happen but...) */
-    for( recno = urec->r.uid.siglist; recno; recno = rec.r.sig.next ) {
-       int i;
-
-       read_record( recno, &rec, RECTYPE_SIG );
-       for(i=0; i < SIGS_PER_RECORD; i++ ) {
-           TRUSTREC tmp;
-           if( !rec.r.sig.sig[i].lid ) {
-               if( !found_delrec && !delrec.recnum ) {
-                   delrec = rec;
-                   delrecidx = i;
-                   found_delrec=1;
-               }
-               continue; /* skip deleted sigs */
-           }
-           if( rec.r.sig.sig[i].lid == pk_lid ) {
-               if( found_sig ) {
-                   log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-                             (ulong)keyid[1], lid, uidhash[18],
-                              uidhash[19], (ulong)sig->keyid[1],
-                            _("Duplicated certificate - deleted") );
-                   rec.r.sig.sig[i].lid = 0;
-                   rec.dirty = 1;
-                   continue;
-               }
-               found_sig = 1;
-           }
-           if( !recheck && !revoke && (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
-               continue; /* we already checked this signature */
-           if( !recheck && (rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
-               continue; /* we do not have the public key */
-
-           read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
-           if( tmp.rectype == RECTYPE_DIR ) {
-               /* In this case we should now be able to check the signature */
-               rc = check_key_signature( keyblock, signode, NULL );
-               if( !rc ) { /* valid signature */
-                   if( opt.verbose )
-                       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-                               (ulong)keyid[1], lid, uidhash[18],
-                               uidhash[19], (ulong)sig->keyid[1],
-                               revoke? _("Valid certificate revocation")
-                                     : _("Good certificate") );
-                   rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
-                   if( revoke )
-                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
-               }
-               else if( rc == G10ERR_NO_PUBKEY ) {
-                 #if 0 /* fixme: For some reason this really happens? */
-                   if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
-                       log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-                                 (ulong)keyid[1], lid, uidhash[18],
-                                uidhash[19], (ulong)sig->keyid[1],
-                                _("Hmmm, public key lost?") );
-                 #endif
-                   rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
-                   if( revoke )
-                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
-               }
-               else {
-                   log_info("sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
-                               (ulong)keyid[1], lid, uidhash[18],
-                               uidhash[19], (ulong)sig->keyid[1],
-                               revoke? _("Invalid certificate revocation")
-                                     : _("Invalid certificate"),
-                                                   g10_errstr(rc));
-                   rec.r.sig.sig[i].flag = SIGF_CHECKED;
-                   if( revoke )
-                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
-               }
-               rec.dirty = 1;
-           }
-           else if( tmp.rectype == RECTYPE_SDIR ) {
-               /* must check that it is the right one */
-               if( tmp.r.sdir.keyid[0] == sig->keyid[0]
-                   && tmp.r.sdir.keyid[1] == sig->keyid[1]
-                   && (!tmp.r.sdir.pubkey_algo
-                        || tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) {
-                   if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
-                       log_info(_("uid %08lX.%lu/%02X%02X: "
-                               "has shadow dir %lu but is not yet marked.\n"),
-                               (ulong)keyid[1], lid,
-                               uidhash[18], uidhash[19], tmp.recnum );
-                   rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
-                   if( revoke )
-                       rec.r.sig.sig[i].flag |= SIGF_REVOKED;
-                   rec.dirty = 1;
-                   /* fixme: should we verify that the record is
-                    * in the hintlist? - This case here should anyway
-                    * never occur */
-               }
-           }
-           else {
-               log_error(_("sig record %lu[%d] points to wrong record.\n"),
-                           rec.r.sig.sig[i].lid, i );
-               die_invalid_db();
-           }
-       }
-       if( found_delrec && delrec.recnum ) {
-           delrec = rec;
-           found_delrec = 0; /* we only want the first one */
-       }
-       if( rec.dirty ) {
-           write_record( &rec );
-           rec.dirty = 0;
-       }
-    }
-
-    if( found_sig )
-       return;
-
-    /* at this point, we have verified, that the signature is not in
-     * our list of signatures. Add a new record with that signature
-     * and if the public key is there, check the signature. */
-
-    if( !pk_lid ) /* we have already seen that there is no pubkey */
-       rc = G10ERR_NO_PUBKEY;
-    else
-       rc = check_key_signature( keyblock, signode, NULL );
-
-    if( !rc ) { /* valid signature */
-       if( opt.verbose )
-           log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-                         (ulong)keyid[1], lid, uidhash[18],
-                          uidhash[19], (ulong)sig->keyid[1],
-                               revoke? _("Valid certificate revocation")
-                                     : _("Good certificate") );
-       newlid = pk_lid;  /* this is the pk of the signature */
-       newflag = SIGF_CHECKED | SIGF_VALID;
-       if( revoke )
-           newflag |= SIGF_REVOKED;
-    }
-    else if( rc == G10ERR_NO_PUBKEY ) {
-       if( opt.verbose > 1 )
-           log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
-                    (ulong)keyid[1], lid, uidhash[18],
-                     uidhash[19], (ulong)sig->keyid[1], g10_errstr(rc) );
-       newlid = create_shadow_dir( sig, lid );
-       newflag = SIGF_NOPUBKEY;
-       if( revoke )
-           newflag |= SIGF_REVOKED;
-    }
-    else {
-       log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
-                   (ulong)keyid[1], lid, uidhash[18], uidhash[19],
-                             (ulong)sig->keyid[1],
-               revoke? _("Invalid certificate revocation")
-                     : _("Invalid certificate"),
-                                           g10_errstr(rc));
-       newlid = create_shadow_dir( sig, lid );
-       newflag = SIGF_CHECKED;
-       if( revoke )
-           newflag |= SIGF_REVOKED;
-    }
-
-    if( delrec.recnum ) { /* we can reuse a deleted/unused slot */
-       delrec.r.sig.sig[delrecidx].lid = newlid;
-       delrec.r.sig.sig[delrecidx].flag= newflag;
-       write_record( &delrec );
-    }
-    else { /* must insert a new sig record */
-       TRUSTREC tmp;
-
-       memset( &tmp, 0, sizeof tmp );
-       tmp.recnum = tdbio_new_recnum();
-       tmp.rectype = RECTYPE_SIG;
-       tmp.r.sig.lid = lid;
-       tmp.r.sig.next = urec->r.uid.siglist;
-       tmp.r.sig.sig[0].lid = newlid;
-       tmp.r.sig.sig[0].flag= newflag;
-       write_record( &tmp );
-       urec->r.uid.siglist = tmp.recnum;
-       urec->dirty = 1;
-    }
+  return test_key_hash_table ((KeyHashTable)opaque, kid);
 }
 
 
-/****************
- * Update all the info from the public keyblock.
- * The key must already exist in the keydb.
- * This function is responsible for checking the signatures in cases
- * where the public key is already available.  If we do not have the public
- * key, the check is done by some special code in insert_trust_record().
+/*
+ * Scan all keys and return a key_array of all suitable keys from
+ * kllist.  The caller has to pass keydb handle so that we don't use
+ * to create our own.  Returns either a key_array or NULL in case of
+ * an error.  No results found are indicated by an empty array.
+ * Caller hast to release the returned array.  
  */
-int
-update_trust_record( KBNODE keyblock, int recheck, int *modified )
+static struct key_array *
+validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
+                   struct key_item *klist, u32 curtime, u32 *next_expire)
 {
-    PKT_public_key *primary_pk;
-    KBNODE node;
-    TRUSTREC drec;
-    TRUSTREC krec;
-    TRUSTREC urec;
-    TRUSTREC prec;
-    TRUSTREC helprec;
-    int rc = 0;
-    u32 keyid[2]; /* keyid of primary key */
-    ulong recno, lastrecno;
-    RECNO_LIST recno_list = NULL; /* list of verified records */
-    /* fixme: replace recno_list by a lookup on node->recno */
-
-    if( modified )
-       *modified = 0;
-
-    node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
-    primary_pk = node->pkt->pkt.public_key;
-    rc = get_dir_record( primary_pk, &drec );
-    if( rc )
-       return rc;
-    if( !primary_pk->local_id )
-       primary_pk->local_id = drec.recnum;
-
-    keyid_from_pk( primary_pk, keyid );
-
-    /* fixme: check that the keyblock has a valid structure */
-
-    rc = tdbio_begin_transaction();
-    if( rc )
-       return rc;
-
-    /* update the keys */
-    for( node=keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_PUBLIC_KEY
-           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           upd_key_record( keyblock, node, keyid,
-                           &drec, &recno_list, recheck );
-    }
-    /* update the user IDs */
-    for( node=keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_USER_ID )
-           upd_uid_record( keyblock, node, keyid,
-                           &drec, &recno_list, recheck );
-    }
-
-    /* delete keyrecords from the trustdb which are not anymore used */
-    /* should we really do this, or is it better to keep them and */
-    /* mark as unused? */
-    lastrecno = 0;
-    for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
-       read_record( recno, &krec, RECTYPE_KEY );
-       if( !qry_recno_list( recno_list, recno, RECTYPE_KEY ) ) {
-           /* delete this one */
-           if( !lastrecno ) {
-               drec.r.dir.keylist = krec.r.key.next;
-               drec.dirty = 1;
-           }
-           else {
-               read_record( lastrecno, &helprec, RECTYPE_KEY );
-               helprec.r.key.next = krec.r.key.next;
-               write_record( &helprec );
+  KBNODE keyblock = NULL;
+  struct key_array *keys = NULL;
+  size_t nkeys, maxkeys;
+  int rc;
+  KEYDB_SEARCH_DESC desc;
+  
+  maxkeys = 1000;
+  keys = m_alloc ((maxkeys+1) * sizeof *keys);
+  nkeys = 0;
+  
+  rc = keydb_search_reset (hd);
+  if (rc)
+    {
+      log_error ("keydb_search_reset failed: %s\n", g10_errstr(rc));
+      m_free (keys);
+      return NULL;
+    }
+
+  memset (&desc, 0, sizeof desc);
+  desc.mode = KEYDB_SEARCH_MODE_FIRST;
+  desc.skipfnc = search_skipfnc;
+  desc.skipfncvalue = full_trust;
+  rc = keydb_search (hd, &desc, 1);
+  if (rc == -1)
+    {
+      keys[nkeys].keyblock = NULL;
+      return keys;
+    }
+  if (rc)
+    {
+      log_error ("keydb_search_first failed: %s\n", g10_errstr(rc));
+      m_free (keys);
+      return NULL;
+    }
+  
+  desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */
+  do
+    {
+      PKT_public_key *pk;
+        
+      rc = keydb_get_keyblock (hd, &keyblock);
+      if (rc) 
+        {
+          log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+          m_free (keys);
+          return NULL;
+        }
+      
+      if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY) 
+        {
+          log_debug ("ooops: invalid pkttype %d encountered\n",
+                     keyblock->pkt->pkttype);
+          dump_kbnode (keyblock);
+          release_kbnode(keyblock);
+          continue;
+        }
+
+      /* prepare the keyblock for further processing */
+      merge_keys_and_selfsig (keyblock); 
+      clear_kbnode_flags (keyblock);
+      pk = keyblock->pkt->pkt.public_key;
+      if (pk->has_expired || pk->is_revoked)
+        {
+          /* it does not make sense to look further at those keys */
+          mark_keyblock_seen (full_trust, keyblock);
+        }
+      else if (validate_one_keyblock (keyblock, klist, curtime, next_expire))
+        {
+         KBNODE node;
+
+          if (pk->expiredate && pk->expiredate >= curtime
+              && pk->expiredate < *next_expire)
+            *next_expire = pk->expiredate;
+
+          if (nkeys == maxkeys) {
+            maxkeys += 1000;
+            keys = m_realloc (keys, (maxkeys+1) * sizeof *keys);
+          }
+          keys[nkeys++].keyblock = keyblock;
+
+         /* Optimization - if all uids are fully trusted, then we
+            never need to consider this key as a candidate again. */
+
+         for (node=keyblock; node; node = node->next)
+           if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 4))
+             break;
+
+         if(node==NULL)
+           mark_keyblock_seen (full_trust, keyblock);
+
+          keyblock = NULL;
+        }
+
+      release_kbnode (keyblock);
+      keyblock = NULL;
+    } 
+  while ( !(rc = keydb_search (hd, &desc, 1)) );
+  if (rc && rc != -1) 
+    {
+      log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
+      m_free (keys);
+      return NULL;
+    }
+
+  keys[nkeys].keyblock = NULL;
+  return keys;
+} 
+
+/* Caller must sync */
+static void
+reset_trust_records(void)
+{
+  TRUSTREC rec;
+  ulong recnum;
+  int count = 0, nreset = 0;
+
+  for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ ) 
+    {
+      if(rec.rectype==RECTYPE_TRUST)
+       {
+         count++;
+         if(rec.r.trust.min_ownertrust)
+           {
+             rec.r.trust.min_ownertrust=0;
+             write_record(&rec);
            }
-           delete_record( recno );
+
        }
-       else
-           lastrecno = recno;
-    }
-    /* delete uid records and sig and their pref records from the
-     * trustdb which are not anymore used */
-    lastrecno = 0;
-    for( recno=drec.r.dir.uidlist; recno; recno = urec.r.uid.next ) {
-       read_record( recno, &urec, RECTYPE_UID );
-       if( !qry_recno_list( recno_list, recno, RECTYPE_UID ) ) {
-           ulong r2;
-           /* delete this one */
-           if( !lastrecno ) {
-               drec.r.dir.uidlist = urec.r.uid.next;
-               drec.dirty = 1;
-           }
-           else {
-               read_record( lastrecno, &helprec, RECTYPE_UID );
-               helprec.r.uid.next = urec.r.uid.next;
-               write_record( &helprec );
-           }
-           for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) {
-               read_record( r2, &prec, RECTYPE_PREF );
-               delete_record( r2 );
-           }
-           for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) {
-               read_record( r2, &helprec, RECTYPE_SIG );
-               delete_record( r2 );
-           }
-           delete_record( recno );
+      else if(rec.rectype==RECTYPE_VALID
+             && ((rec.r.valid.validity&TRUST_MASK)
+                 || rec.r.valid.marginal_count
+                 || rec.r.valid.full_count))
+       {
+         rec.r.valid.validity &= ~TRUST_MASK;
+         rec.r.valid.marginal_count=rec.r.valid.full_count=0;
+         nreset++;
+         write_record(&rec);
        }
-       else
-           lastrecno = recno;
-    }
 
-
-
-    if( rc )
-       rc = tdbio_cancel_transaction();
-    else {
-       drec.r.dir.dirflags |= DIRF_CHECKED;
-       drec.r.dir.dirflags &= ~DIRF_VALVALID;
-       write_record( &drec );
-       if( modified && tdbio_is_dirty() )
-           *modified = 1;
-       rc = tdbio_end_transaction();
     }
-    rel_recno_list( &recno_list );
-    return rc;
-}
 
+  if (opt.verbose)
+    log_info (_("%d keys processed (%d validity counts cleared)\n"),
+             count, nreset);
+}
 
-/****************
- * Insert a trust record into the TrustDB
- * This function assumes that the record does not yet exist.
+/*
+ * Run the key validation procedure.
+ *
+ * This works this way:
+ * Step 1: Find all ultimately trusted keys (UTK).
+ *         mark them all as seen and put them into klist.
+ * Step 2: loop max_cert_times
+ * Step 3:   if OWNERTRUST of any key in klist is undefined
+ *             ask user to assign ownertrust
+ * Step 4:   Loop over all keys in the keyDB which are not marked seen 
+ * Step 5:     if key is revoked or expired
+ *                mark key as seen
+ *                continue loop at Step 4
+ * Step 6:     For each user ID of that key signed by a key in klist
+ *                Calculate validity by counting trusted signatures.
+ *                Set validity of user ID
+ * Step 7:     If any signed user ID was found
+ *                mark key as seen
+ *             End Loop
+ * Step 8:   Build a new klist from all fully trusted keys from step 6
+ *           End Loop
+ *         Ready  
+ *
  */
-int
-insert_trust_record( PKT_public_key *pk )
+static int
+validate_keys (int interactive)
 {
-    TRUSTREC dirrec;
-    TRUSTREC shadow;
-    KBNODE keyblock = NULL;
-    KBNODE node;
-    byte fingerprint[MAX_FINGERPRINT_LEN];
-    size_t fingerlen;
-    int rc = 0;
-    ulong hintlist = 0;
-
-    if( pk->local_id )
-       log_bug("pk->local_id=%lu\n", pk->local_id );
-
-    fingerprint_from_pk( pk, fingerprint, &fingerlen );
-
-    /* fixme: assert that we do not have this record.
-     * we can do this by searching for the primary keyid
-     *
-     * fixme: If there is no such key we should look whether one
-     * of the subkeys has been used to sign another key and in this case
-     * we got the key anyway.  Because a secondary key can't be used
-     * without a primary key (it is needed to bind the secondary one
-     * to the primary one which has the user ids etc.)
-     */
-
-    /* get the keyblock which has the key */
-    rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
-    if( rc ) { /* that should never happen */
-       log_error( _("insert_trust_record: keyblock not found: %s\n"),
-                                                         g10_errstr(rc) );
-       goto leave;
-    }
-
-    /* check that we used the primary key (we are little bit paranoid) */
-    {  PKT_public_key *a_pk;
-       u32 akid[2], bkid[2];
-
-       node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
-       a_pk = node->pkt->pkt.public_key;
-
-       /* we can't use cmp_public_keys here because some parts (expiredate)
-        * might not be set in pk <--- but why (fixme) */
-       keyid_from_pk( a_pk, akid );
-       keyid_from_pk( pk, bkid );
+  int rc = 0;
+  int quit=0;
+  struct key_item *klist = NULL;
+  struct key_item *k;
+  struct key_array *keys = NULL;
+  struct key_array *kar;
+  KEYDB_HANDLE kdb = NULL;
+  KBNODE node;
+  int depth;
+  int ot_unknown, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate;
+  KeyHashTable stored,used,full_trust;
+  u32 start_time, next_expire;
+
+  /* Make sure we have all sigs cached.  TODO: This is going to
+     require some architectual re-thinking, as it is agonizingly slow.
+     Perhaps combine this with reset_trust_records(), or only check
+     the caches on keys that are actually involved in the web of
+     trust. */
+  keydb_rebuild_caches(0);
+
+  start_time = make_timestamp ();
+  next_expire = 0xffffffff; /* set next expire to the year 2106 */
+  stored = new_key_hash_table ();
+  used = new_key_hash_table ();
+  full_trust = new_key_hash_table ();
+
+  kdb = keydb_new (0);
+  reset_trust_records();
+
+  /* Fixme: Instead of always building a UTK list, we could just build it
+   * here when needed */
+  if (!utk_list)
+    {
+      log_info (_("no ultimately trusted keys found\n"));
+      goto leave;
+    }
+
+  /* mark all UTKs as used and fully_trusted and set validity to
+     ultimate */
+  for (k=utk_list; k; k = k->next)
+    {
+      KBNODE keyblock;
+      PKT_public_key *pk;
+
+      keyblock = get_pubkeyblock (k->kid);
+      if (!keyblock)
+        {
+          log_error (_("public key of ultimately"
+                       " trusted key %s not found\n"), keystr(k->kid));
+          continue;
+        }
+      mark_keyblock_seen (used, keyblock);
+      mark_keyblock_seen (stored, keyblock);
+      mark_keyblock_seen (full_trust, keyblock);
+      pk = keyblock->pkt->pkt.public_key;
+      for (node=keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_USER_ID)
+           update_validity (pk, node->pkt->pkt.user_id, 0, TRUST_ULTIMATE);
+        }
+      if ( pk->expiredate && pk->expiredate >= start_time
+           && pk->expiredate < next_expire)
+        next_expire = pk->expiredate;
+      
+      release_kbnode (keyblock);
+      do_sync ();
+    }
+
+  klist = utk_list;
+
+  log_info(_("%d marginal(s) needed, %d complete(s) needed, %s trust model\n"),
+          opt.marginals_needed,opt.completes_needed,trust_model_string());
+
+  for (depth=0; depth < opt.max_cert_depth; depth++)
+    {
+      int valids=0,key_count;
+      /* See whether we should assign ownertrust values to the keys in
+         klist.  */
+      ot_unknown = ot_undefined = ot_never = 0;
+      ot_marginal = ot_full = ot_ultimate = 0;
+      for (k=klist; k; k = k->next)
+        {
+         int min=0;
+
+         /* 120 and 60 are as per RFC2440 */
+         if(k->trust_value>=120)
+           min=TRUST_FULLY;
+         else if(k->trust_value>=60)
+           min=TRUST_MARGINAL;
+
+         if(min!=k->min_ownertrust)
+           update_min_ownertrust(k->kid,min);
+
+          if (interactive && k->ownertrust == TRUST_UNKNOWN)
+           {
+             k->ownertrust = ask_ownertrust (k->kid,min);
+
+             if (k->ownertrust == -1)
+               {
+                 quit=1;
+                 goto leave;
+               }
+           }
 
-       if( akid[0] != bkid[0] || akid[1] != bkid[1] ) {
-           log_error(_("did not use primary key for insert_trust_record()\n"));
-           rc = G10ERR_GENERAL;
-           goto leave;
-       }
-    }
+         /* This can happen during transition from an old trustdb
+            before trust sigs.  It can also happen if a user uses two
+            different versions of GnuPG or changes the --trust-model
+            setting. */
+         if(k->ownertrust<min)
+           {
+             if(DBG_TRUST)
+               log_debug("key %08lX%08lX:"
+                         " overriding ownertrust `%s' with `%s'\n",
+                         (ulong)k->kid[0],(ulong)k->kid[1],
+                         trust_value_to_string(k->ownertrust),
+                         trust_value_to_string(min));
+
+             k->ownertrust=min;
+           }
 
-    /* We have to look for a shadow dir record which must be reused
-     * as the dir record. And: check all signatures which are listed
-     * in the hintlist of the shadow dir record.
-     */
-    rc = tdbio_search_sdir( pk->keyid, pk->pubkey_algo, &shadow );
-    if( rc && rc != -1 ) {
-       log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
-       die_invalid_db();
-    }
-    memset( &dirrec, 0, sizeof dirrec );
-    dirrec.rectype = RECTYPE_DIR;
-    if( !rc ) {
-       /* hey, great: this key has already signed other keys
-        * convert this to a real directory entry */
-       hintlist = shadow.r.sdir.hintlist;
-       dirrec.recnum = shadow.recnum;
-    }
-    else {
-       dirrec.recnum = tdbio_new_recnum();
-    }
-    dirrec.r.dir.lid = dirrec.recnum;
-    write_record( &dirrec );
-
-    /* store the LID */
-    pk->local_id = dirrec.r.dir.lid;
-    for( node=keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_PUBLIC_KEY
-           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
-           PKT_public_key *pk = node->pkt->pkt.public_key;
-           pk->local_id = dirrec.r.dir.lid;
-       }
-       else if( node->pkt->pkttype == PKT_SIGNATURE ) {
-           PKT_signature *sig = node->pkt->pkt.signature;
-           sig->local_id = dirrec.r.dir.lid;
+         if (k->ownertrust == TRUST_UNKNOWN)
+            ot_unknown++;
+          else if (k->ownertrust == TRUST_UNDEFINED)
+            ot_undefined++;
+          else if (k->ownertrust == TRUST_NEVER)
+            ot_never++;
+          else if (k->ownertrust == TRUST_MARGINAL)
+            ot_marginal++;
+          else if (k->ownertrust == TRUST_FULLY)
+            ot_full++;
+          else if (k->ownertrust == TRUST_ULTIMATE)
+            ot_ultimate++;
+
+         valids++;
+        }
+
+      /* Find all keys which are signed by a key in kdlist */
+      keys = validate_key_list (kdb, full_trust, klist,
+                               start_time, &next_expire);
+      if (!keys) 
+        {
+          log_error ("validate_key_list failed\n");
+          rc = G10ERR_GENERAL;
+          goto leave;
+        }
+
+      for (key_count=0, kar=keys; kar->keyblock; kar++, key_count++)
+        ;
+
+      /* Store the calculated valididation status somewhere */
+      if (opt.verbose > 1)
+        dump_key_array (depth, keys);
+
+      for (kar=keys; kar->keyblock; kar++)
+          store_validation_status (depth, kar->keyblock, stored);
+
+      log_info (_("depth: %d  valid: %3d  signed: %3d"
+                  "  trust: %d-, %dq, %dn, %dm, %df, %du\n"), 
+                depth, valids, key_count, ot_unknown, ot_undefined,
+                ot_never, ot_marginal, ot_full, ot_ultimate ); 
+
+      /* Build a new kdlist from all fully valid keys in KEYS */
+      if (klist != utk_list)
+        release_key_items (klist);
+      klist = NULL;
+      for (kar=keys; kar->keyblock; kar++)
+        {
+          for (node=kar->keyblock; node; node = node->next)
+            {
+              if (node->pkt->pkttype == PKT_USER_ID && (node->flag & 4))
+                {
+                 u32 kid[2];
+
+                 /* have we used this key already? */
+                  keyid_from_pk (kar->keyblock->pkt->pkt.public_key, kid);
+                 if(test_key_hash_table(used,kid)==0)
+                   {
+                     /* Normally we add both the primary and subkey
+                        ids to the hash via mark_keyblock_seen, but
+                        since we aren't using this hash as a skipfnc,
+                        that doesn't matter here. */
+                     add_key_hash_table (used,kid);
+                     k = new_key_item ();
+                     k->kid[0]=kid[0];
+                     k->kid[1]=kid[1];
+                     k->ownertrust =
+                       (get_ownertrust (kar->keyblock->pkt->pkt.public_key)
+                        & TRUST_MASK);
+                     k->min_ownertrust =
+                       get_min_ownertrust(kar->keyblock->pkt->pkt.public_key);
+                     k->trust_depth=
+                       kar->keyblock->pkt->pkt.public_key->trust_depth;
+                     k->trust_value=
+                       kar->keyblock->pkt->pkt.public_key->trust_value;
+                     if(kar->keyblock->pkt->pkt.public_key->trust_regexp)
+                       k->trust_regexp=
+                         m_strdup(kar->keyblock->pkt->
+                                  pkt.public_key->trust_regexp);
+                     k->next = klist;
+                     klist = k;
+                     break;
+                   }
+               }
+           }
        }
-    }
-
-    /* and put all the other stuff into the keydb */
-    rc = update_trust_record( keyblock, 1, NULL );
-    if( !rc )
-       process_hintlist( hintlist, dirrec.r.dir.lid );
-
-  leave:
-    if( rc && hintlist )
-       ; /* fixme: the hintlist is not anymore anchored */
-    release_kbnode( keyblock );
-    do_sync();
-    return rc;
-}
-
-
-int
-update_ownertrust( ulong lid, unsigned new_trust )
-{
-    TRUSTREC rec;
-
-    read_record( lid, &rec, RECTYPE_DIR );
-    rec.r.dir.ownertrust = new_trust;
-    write_record( &rec );
-    do_sync();
-    return 0;
+      release_key_array (keys);
+      keys = NULL;
+      if (!klist)
+        break; /* no need to dive in deeper */
+    }
+
+ leave:
+  keydb_release (kdb);
+  release_key_array (keys);
+  release_key_items (klist);
+  release_key_hash_table (full_trust);
+  release_key_hash_table (used);
+  release_key_hash_table (stored);
+  if (!rc && !quit) /* mark trustDB as checked */
+    {
+      if (next_expire == 0xffffffff || next_expire < start_time )
+        tdbio_write_nextcheck (0); 
+      else
+        {
+          tdbio_write_nextcheck (next_expire); 
+          log_info (_("next trustdb check due at %s\n"),
+                    strtimestamp (next_expire));
+        }
+
+      if(tdbio_update_version_record()!=0)
+       {
+         log_error(_("unable to update trustdb version record: "
+                     "write failed: %s\n"), g10_errstr(rc));
+         tdbio_invalid();
+       }
+
+      do_sync ();
+      pending_check_trustdb = 0;
+    }
+
+  return rc;
 }
-
-