See ChangeLog: Thu Jan 21 06:22:10 CET 1999 Werner Koch
[gnupg.git] / g10 / trustdb.c
index cc768d5..674240a 100644 (file)
@@ -1,14 +1,14 @@
 /* trustdb.c
  *     Copyright (C) 1998 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
 #include "i18n.h"
 #include "tdbio.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;
@@ -66,7 +70,7 @@ typedef struct trust_info TRUST_INFO;
 struct trust_info {
     ulong    lid;
     byte     otrust; /* ownertrust (assigned trust) */
-    byte     trust; /* calculated trust (validity) */
+    byte     trust;  /* calculated trust (validity) */
 };
 
 typedef struct trust_seg_list *TRUST_SEG_LIST;
@@ -77,6 +81,13 @@ struct trust_seg_list {
 };
 
 
+struct enum_cert_paths_ctx {
+   int init;
+   TRUST_SEG_LIST tsl_head;
+   TRUST_SEG_LIST tsl;
+   int idx;
+};
+
 
 struct recno_list_struct {
     struct recno_list_struct *next;
@@ -94,6 +105,7 @@ 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 );
@@ -103,9 +115,10 @@ 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 struct keyid_list *trusted_key_list;
 
 /* a table used to keep track of ultimately trusted keys
- * which are the ones from our secrings */
+ * which are the ones from our secrings and the trusted keys */
 static LOCAL_ID_TABLE ultikey_table;
 
 /* list of unused lid items and tables */
@@ -126,7 +139,7 @@ static void
 die_invalid_db()
 {
     log_error(_(
-       "The trust DB is corrupted; please run \"gpgm --fix-trust-db\".\n") );
+       "The trustdb is corrupted; please run \"gpgm --fix-trustdb\".\n") );
     g10_exit(2);
 }
 
@@ -139,7 +152,7 @@ read_record( ulong recno, TRUSTREC *rec, int rectype )
     int rc = tdbio_read_record( recno, rec, rectype );
     if( !rc )
        return;
-    log_error("trust record %lu, req type %d: read failed: %s\n",
+    log_error(_("trust record %lu, req type %d: read failed: %s\n"),
                                    recno, rectype,  g10_errstr(rc) );
     die_invalid_db();
 }
@@ -154,7 +167,7 @@ write_record( TRUSTREC *rec )
     int rc = tdbio_write_record( rec );
     if( !rc )
        return;
-    log_error("trust record %lu, type %d: write failed: %s\n",
+    log_error(_("trust record %lu, type %d: write failed: %s\n"),
                            rec->recnum, rec->rectype, g10_errstr(rc) );
     die_invalid_db();
 }
@@ -168,7 +181,7 @@ delete_record( ulong recno )
     int rc = tdbio_delete_record( recno );
     if( !rc )
        return;
-    log_error("trust record %lu: delete failed: %s\n",
+    log_error(_("trust record %lu: delete failed: %s\n"),
                                              recno, g10_errstr(rc) );
     die_invalid_db();
 }
@@ -182,7 +195,7 @@ do_sync( )
     int rc = tdbio_sync();
     if( !rc )
        return;
-    log_error("trust db: sync failed: %s\n", g10_errstr(rc) );
+    log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
     g10_exit(2);
 }
 
@@ -237,7 +250,7 @@ new_lid_table(void)
     a = unused_lid_tables;
     if( a ) {
        unused_lid_tables = a->next;
-       a->next = NULL;
+       memset( a, 0, sizeof *a );
     }
     else
        a = m_alloc_clear( sizeof *a );
@@ -311,24 +324,24 @@ keyid_from_lid( ulong lid, u32 *keyid )
 
     rc = tdbio_read_record( lid, &rec, 0 );
     if( rc ) {
-       log_error("error reading dir record for LID %lu: %s\n",
+       log_error(_("error reading dir record for LID %lu: %s\n"),
                                                    lid, g10_errstr(rc));
        return G10ERR_TRUSTDB;
     }
     if( rec.rectype == RECTYPE_SDIR )
        return 0;
     if( rec.rectype != RECTYPE_DIR ) {
-       log_error("lid %lu: expected dir record, got type %d\n",
+       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 );
+       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",
+       log_error(_("error reading primary key for LID %lu: %s\n"),
                                                    lid, g10_errstr(rc));
        return G10ERR_TRUSTDB;
     }
@@ -424,9 +437,45 @@ walk_sigrecs( SIGREC_CONTEXT *c )
  ************* Trust  stuff  ******************
  ***********************************************/
 
+static int
+trust_letter( unsigned 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 ;
+    }
+}
+
+
+void
+register_trusted_key( const char *string )
+{
+    u32 keyid[2];
+    struct keyid_list *r;
+
+    if( classify_user_id( string, keyid, NULL, NULL, NULL ) != 11 ) {
+       log_error(_("'%s' is not a valid long keyID\n"), string );
+       return;
+    }
+
+    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;
+}
 
 /****************
- * Verify that all our public keys are in the trustDB.
+ * Verify that all our public keys are in the trustdb.
  */
 static int
 verify_own_keys()
@@ -436,17 +485,62 @@ verify_own_keys()
     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]);
+           }
+       }
+       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",
+           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 );
@@ -455,6 +549,7 @@ verify_own_keys()
                                                            (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"),
@@ -482,20 +577,30 @@ verify_own_keys()
            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 secret key table\n"),
+           log_error(_("key %08lX: already in trusted key table\n"),
                                                        (ulong)keyid[1]);
-       else if( opt.verbose )
-           log_info(_("key %08lX: accepted as secret key.\n"),
+       else if( opt.verbose > 1 )
+           log_info(_("key %08lX: accepted as trusted key.\n"),
                                                        (ulong)keyid[1]);
       skip:
        release_secret_key_parts( sk );
-       release_public_key_parts( pk );
+       if( have_pk )
+           release_public_key_parts( pk );
     }
     if( rc != -1 )
-       log_error(_("enum_secret_keys failed: %s\n"), g10_errstr(rc) );
+       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;
+    }
+
     enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
     free_secret_key( sk );
     free_public_key( pk );
@@ -666,7 +771,8 @@ list_records( ulong lid )
 
     rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
     if( rc ) {
-       log_error("lid %lu: read dir record failed: %s\n", lid, g10_errstr(rc));
+       log_error(_("lid %lu: read dir record failed: %s\n"),
+                                               lid, g10_errstr(rc));
        return rc;
     }
     tdbio_dump_record( &dr, stdout );
@@ -674,7 +780,7 @@ list_records( ulong lid )
     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",
+           log_error(_("lid %lu: read key record failed: %s\n"),
                                                lid, g10_errstr(rc));
            return rc;
        }
@@ -684,7 +790,7 @@ list_records( ulong lid )
     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",
+           log_error(_("lid %lu: read uid record failed: %s\n"),
                                                lid, g10_errstr(rc));
            return rc;
        }
@@ -693,7 +799,7 @@ list_records( ulong lid )
        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",
+               log_error(_("lid %lu: read pref record failed: %s\n"),
                                                    lid, g10_errstr(rc));
                return rc;
            }
@@ -703,7 +809,7 @@ list_records( ulong lid )
        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",
+               log_error(_("lid %lu: read sig record failed: %s\n"),
                                                    lid, g10_errstr(rc));
                return rc;
            }
@@ -737,22 +843,23 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
 
     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) */
     }
-
-    stack[depth].lid = drec->r.dir.lid;
-    stack[depth].otrust = drec->r.dir.ownertrust;
-    stack[depth].trust = 0;
     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 ) );
@@ -791,27 +898,34 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
            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) )
-                   continue; /* skip unchecked signatures */
-               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 */
+               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 multizple user IDs */
+                * signed more than one user ID) */
                if( sigs_seen && ins_lid_table_item( sigs_seen,
                                                     rec.r.sig.sig[i].lid, 0) )
-                   continue; /* we alread have this one */
+                   continue; /* we already have this one */
 
                read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
                if( tmp.rectype != RECTYPE_DIR ) {
-                   log_info("oops: lid %lu: sig %lu has rectype %d"
+                   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;
@@ -823,7 +937,7 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
                                                        trust_seg_head );
                nt &= TRUST_MASK;
 
-               if( nt < TRUST_MARGINAL ) {
+               if( nt < TRUST_MARGINAL || unchecked ) {
                    continue;
                }
 
@@ -837,6 +951,9 @@ collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
                    }
                }
 
+               if( nt > ot )
+                   nt = ot;
+
                if( nt >= TRUST_FULLY )
                    fully++;
                if( nt >= TRUST_MARGINAL )
@@ -890,21 +1007,34 @@ verify_key( int max_depth, TRUSTREC *drec )
  * but nothing more is known.
  */
 static int
-do_check( TRUSTREC *dr, unsigned *trustlevel )
+do_check( TRUSTREC *dr, unsigned *validity )
 {
     if( !dr->r.dir.keylist ) {
-       log_error("Ooops, no keys\n");
+       log_error(_("Ooops, no keys\n"));
        return G10ERR_TRUSTDB;
     }
     if( !dr->r.dir.uidlist ) {
-       log_error("Ooops, no user ids\n");
+       log_error(_("Ooops, no user ids\n"));
        return G10ERR_TRUSTDB;
     }
 
-    *trustlevel = verify_key( 5, dr );
+    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 )
-       *trustlevel |= TRUST_FLAG_REVOKED;
+       *validity |= TRUST_FLAG_REVOKED;
 
     return 0;
 }
@@ -955,25 +1085,29 @@ list_trustdb( const char *username )
        ulong lid = atoi(username+1);
 
        if( (rc = list_records( lid)) )
-           log_error("user '%s' read problem: %s\n", username, g10_errstr(rc));
+           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));
+           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( pk, username )) )
-           log_error("user '%s' not found: %s\n", username, g10_errstr(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",
+           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);
+           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));
+           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));
+           log_error(_("user '%s' list problem: %s\n"),
+                                               username, g10_errstr(rc));
        free_public_key( pk );
     }
     else {
@@ -1002,20 +1136,20 @@ export_ownertrust()
     byte *p;
     int rc;
 
-    printf("# List of assigned trustvalues, created %s\n"
-          "# (Use \"gpgm --import-ownertrust\" to restore them)\n",
+    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("Oops; directory record w/o primary key\n");
+               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));
+               log_error(_("error reading key record: %s\n"), g10_errstr(rc));
                continue;
            }
            p = rec2.r.key.fingerprint;
@@ -1055,7 +1189,7 @@ import_ownertrust( const char *fname )
            continue;
        n = strlen(line);
        if( line[n-1] != '\n' ) {
-           log_error_f(fname, "line to long\n" );
+           log_error_f(fname, _("line too long\n") );
            /* ... or last line does not have a LF */
            break; /* can't continue */
        }
@@ -1063,16 +1197,16 @@ import_ownertrust( const char *fname )
            if( !isxdigit(*p) )
                break;
        if( *p != ':' ) {
-           log_error_f(fname, "error: missing colon\n" );
+           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" );
+           log_error_f(fname, _("error: invalid fingerprint\n") );
            continue;
        }
        if( sscanf(p, ":%u:", &otrust ) != 1 ) {
-           log_error_f(fname, "error: no otrust value\n" );
+           log_error_f(fname, _("error: no ownertrust value\n") );
            continue;
        }
        if( !otrust )
@@ -1097,25 +1231,25 @@ import_ownertrust( const char *fname )
        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");
+           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));
+               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");
+                   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",
+                   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",
+           log_error_f(fname, _("error finding dir record: %s\n"),
                                                    g10_errstr(rc));
     }
     if( ferror(fp) )
@@ -1129,52 +1263,96 @@ import_ownertrust( const char *fname )
 
 
 static void
-print_path( int pathlen, TRUST_INFO *path )
+print_path( int pathlen, TRUST_INFO *path, FILE *fp, ulong highlight )
 {
-    int rc, i;
+    int rc, c, i;
     u32 keyid[2];
+    char *p;
+    size_t n;
 
-    fputs("path:", stdout);
     for( i = 0; i < pathlen; i++ )  {
-       if( i && !(i%4) )
-           fputs("     ", stdout );
+       if( highlight )
+           fputs(highlight == path[i].lid? "* ":"  ", fp );
        rc = keyid_from_lid( path[i].lid, keyid );
        if( rc )
-           printf(" ????????.%lu:", path[i].lid );
+           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
-           printf(" %08lX.%lu:", (ulong)keyid[1], path[i].lid );
-       print_sigflags( stdout, path[i].otrust );
+           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 );
     }
-    putchar('\n');
 }
 
 
+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;
+}
+
+
+static void
+sort_tsl_list( TRUST_SEG_LIST *trust_seg_list )
+{
+    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 );
+}
+
 
 void
-list_trust_path( int max_depth, const char *username )
+list_trust_path( const char *username )
 {
     int rc;
-    int wipe=0;
     TRUSTREC rec;
     TRUST_INFO *tmppath;
     TRUST_SEG_LIST trust_seg_list, tsl, tsl2;
     PKT_public_key *pk = m_alloc_clear( sizeof *pk );
 
-    if( max_depth < 0 ) {
-       wipe = 1;
-       max_depth = -max_depth;
-    }
-
-    if( (rc = get_pubkey_byname( pk, username )) )
-       log_error("user '%s' not found: %s\n", username, g10_errstr(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",
+       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);
+       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));
+           log_error(_("failed to put '%s' into trustdb: %s\n"),
+                                                   username, g10_errstr(rc));
        else {
            assert( pk->local_id );
        }
@@ -1182,13 +1360,16 @@ list_trust_path( int max_depth, const char *username )
     free_public_key( pk );
 
     /* collect the paths */
-    tmppath = m_alloc_clear( (max_depth+1)* sizeof *tmppath );
+    tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
     trust_seg_list = NULL;
-    collect_paths( 0, max_depth, 1, &rec, tmppath, &trust_seg_list );
+    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 );
+       print_path( tsl->pathlen, tsl->path, stdout, 0 );
+       if( tsl->next )
+           putchar('\n');
     }
 
     /* release the list */
@@ -1202,7 +1383,9 @@ list_trust_path( int max_depth, const char *username )
 
 /****************
  * Check the complete trustdb or only the entries for the given username.
- * We check the complete database and recalculate all flags.
+ * 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 )
@@ -1211,19 +1394,20 @@ check_trustdb( const char *username )
     KBNODE keyblock = NULL;
     KBPOS kbpos;
     int rc;
+    int recheck = username && *username == '*' && !username[1];
 
-    if( username ) {
+    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",
+           log_error(_("%s: keyblock read problem: %s\n"),
                                    username, g10_errstr(rc));
        }
        else {
            int modified;
 
-           rc = update_trust_record( keyblock, 0, &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
@@ -1231,12 +1415,12 @@ check_trustdb( const char *username )
 
            }
            if( rc )
-               log_error("%s: update failed: %s\n",
+               log_error(_("%s: update failed: %s\n"),
                                           username, g10_errstr(rc) );
            else if( modified )
-               log_info("%s: updated\n", username );
+               log_info(_("%s: updated\n"), username );
            else
-               log_info("%s: okay\n", username );
+               log_info(_("%s: okay\n"), username );
 
        }
        release_kbnode( keyblock ); keyblock = NULL;
@@ -1251,7 +1435,8 @@ check_trustdb( const char *username )
                int modified;
 
                if( !rec.r.dir.keylist ) {
-                   log_info("lid %lu: dir record w/o key - skipped\n", recnum);
+                   log_info(_("lid %lu: dir record w/o key - skipped\n"),
+                                                                 recnum);
                    count++;
                    skip_count++;
                    continue;
@@ -1263,26 +1448,26 @@ check_trustdb( const char *username )
                                            tmp.r.key.fingerprint,
                                            tmp.r.key.fingerprint_len );
                if( rc ) {
-                   log_error("lid %lu: keyblock not found: %s\n",
+                   log_error(_("lid %lu: keyblock not found: %s\n"),
                                                 recnum, g10_errstr(rc) );
                    count++;
                    skip_count++;
                    continue;
                }
 
-               rc = update_trust_record( keyblock, 0, &modified );
+               rc = update_trust_record( keyblock, recheck, &modified );
                if( rc ) {
-                   log_error("lid %lu: update failed: %s\n",
+                   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 );
+                       log_info(_("lid %lu: updated\n"), recnum );
                    upd_count++;
                }
                else if( opt.verbose > 1 )
-                   log_info("lid %lu: okay\n", recnum );
+                   log_info(_("lid %lu: okay\n"), recnum );
 
                release_kbnode( keyblock ); keyblock = NULL;
                if( !(++count % 100) )
@@ -1325,33 +1510,33 @@ update_trustdb( )
                                       ) ->pkt->pkt.public_key;
                rc = insert_trust_record( pk );
                if( rc && !pk->local_id ) {
-                   log_error("lid ?: insert failed: %s\n",
+                   log_error(_("lid ?: insert failed: %s\n"),
                                                     g10_errstr(rc) );
                    err_count++;
                }
                else if( rc ) {
-                   log_error("lid %lu: insert failed: %s\n",
+                   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 );
+                       log_info(_("lid %lu: inserted\n"), pk->local_id );
                    new_count++;
                }
            }
            else if( rc ) {
-               log_error("lid %lu: update failed: %s\n",
+               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));
+                   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) );
+               log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) );
 
            release_kbnode( keyblock ); keyblock = NULL;
            if( !(++count % 100) )
@@ -1366,7 +1551,7 @@ update_trustdb( )
            log_info(_("\t%lu keys inserted\n"), new_count);
     }
     if( rc && rc != -1 )
-       log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
+       log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
 
     enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
     release_kbnode( keyblock );
@@ -1411,7 +1596,7 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel )
     }
     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",
+           log_error(_("check_trust: search dir record failed: %s\n"),
                                                            g10_errstr(rc));
            return rc;
        }
@@ -1460,6 +1645,8 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel )
 }
 
 
+
+
 int
 query_trust_info( PKT_public_key *pk )
 {
@@ -1470,16 +1657,9 @@ query_trust_info( PKT_public_key *pk )
        return '?';
     if( trustlevel & TRUST_FLAG_REVOKED )
        return 'r';
-    switch( (trustlevel & TRUST_MASK) ) {
-      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: BUG();
-    }
+    c = trust_letter( (trustlevel & TRUST_MASK) );
+    if( !c )
+       c = '?';
     return c;
 }
 
@@ -1488,7 +1668,10 @@ query_trust_info( PKT_public_key *pk )
 /****************
  * Enumerate all keys, which are needed to build all trust paths for
  * the given key.  This function does not return the key itself or
- * the ultimate key.
+ * the ultimate key (the last point in cerificate chain).  Only
+ * certificate chains which ends up at an ultimately trusted key
+ * are listed. If ownertrust or validity is not NULL, the corresponding
+ * value for the returned LID is also returned in these variable(s).
  *
  *  1) create a void pointer and initialize it to NULL
  *  2) pass this void pointer by reference to this function.
@@ -1497,13 +1680,113 @@ query_trust_info( PKT_public_key *pk )
  *     to indicate EOF. LID does contain the next key used to build the web
  *  4) Always call this function a last time with LID set to NULL,
  *     so that it can free its context.
+ *
+ * Returns: -1 on EOF or the level of the returned LID
  */
 int
-enum_trust_web( void **context, ulong *lid )
+enum_cert_paths( void **context, ulong *lid,
+                unsigned *ownertrust, unsigned *validity )
 {
-    /* REPLACE THIS with a BETTER ONE  */
+    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;
 
-    return -1; /* eof */
+       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;
+}
+
+
+/****************
+ * Print the current path
+ */
+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 );
 }
 
 
@@ -1526,17 +1809,21 @@ get_ownertrust_info( ulong lid )
     int c;
 
     otrust = get_ownertrust( lid );
-    switch( (otrust & TRUST_MASK) ) {
-      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:             c = '-'; break;
-    }
+    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 )
 {
@@ -1552,7 +1839,7 @@ get_pref_data( ulong lid, const byte *namehash, size_t *ret_n )
            /* 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");
+               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;
@@ -1581,7 +1868,7 @@ is_algo_in_prefs( ulong lid, int preftype, int algo )
        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");
+               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 )
@@ -1603,7 +1890,7 @@ get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
     }
     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",
+           log_error(_("get_dir_record: search_record failed: %s\n"),
                                                            g10_errstr(rc));
     }
     return rc;
@@ -1613,7 +1900,7 @@ get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
 
 /****************
  * This function simply looks for the key in the trustdb
- * and makes sure that pk->local_id is set to the coreect value.
+ * and makes sure that pk->local_id is set to the correct value.
  * Return: 0 = found
  *        -1 = not found
  *       other = error
@@ -1625,7 +1912,7 @@ query_trust_record( PKT_public_key *pk )
     return get_dir_record( pk, &rec );
 }
 
-/* FIXME: Brauchen wir das?? */
+
 int
 clear_trust_checked_flag( PKT_public_key *pk )
 {
@@ -1636,11 +1923,14 @@ clear_trust_checked_flag( PKT_public_key *pk )
     if( rc )
        return rc;
 
-    if( !(rec.r.dir.dirflags & DIRF_CHECKED) )
+    /* 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;
@@ -1663,11 +1953,11 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
     int revoke = 0;
 
     if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED )
-       log_info(_("note: sig rec %lu[%d] in hintlist "
+       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 "
+       log_info(_("NOTE: sig rec %lu[%d] in hintlist "
                   "of %lu but not marked\n"),
                    sigrec->recnum, sigidx, hint_owner );
 
@@ -1860,13 +2150,13 @@ create_shadow_dir( PKT_signature *sig, ulong lid  )
 {
     TRUSTREC sdir, hlst, tmphlst;
     ulong recno, newlid;
-    int tmpidx;
+    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));
+       log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
        die_invalid_db();
     }
     if( rc == -1 ) { /* not found: create */
@@ -2165,6 +2455,9 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
                    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",
@@ -2176,7 +2469,13 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
            }
            else if( sig->sig_class == 0x30 ) { /* cert revocation */
                rc = check_key_signature( keyblock, node, NULL );
-               if( !rc ) {
+               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],
@@ -2267,14 +2566,16 @@ upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
     for(k=0; ptable[k].subpkttype; k++ ) {
        s = parse_sig_subpkt2( sig, ptable[k].subpkttype, &n );
        if( 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;
+           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;
+               }
+               prefs_sig[n_prefs_sig++] = ptable[k].preftype;
+               prefs_sig[n_prefs_sig++] = *s;
            }
-           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 ) {
@@ -2283,16 +2584,18 @@ upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
            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 preferences items") );
+                         _("Too many preference items") );
                break;
            }
-           prefs_rec[n_prefs_rec++] = prec.r.pref.data[i];
-           prefs_rec[n_prefs_rec++] = prec.r.pref.data[i+1];
+           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( n_prefs_sig == n_prefs_rec
        && !memcmp( prefs_sig, prefs_rec, n_prefs_sig ) )
-       return;  /* not chnaged */
+       return;  /* not changed */
 
     /* Preferences have changed:  Delete all pref records
      * This is much simpler than checking whether we have to
@@ -2304,7 +2607,7 @@ upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
     }
 
     if( n_prefs_sig > ITEMS_PER_PREF_RECORD )
-       log_info("cannot yet handle long preferences");
+        log_info(_("WARNING: can't yet handle long pref records\n"));
 
     memset( &prec, 0, sizeof prec );
     prec.recnum = tdbio_new_recnum();
@@ -2366,7 +2669,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
     TRUSTREC rec;
     ulong recno;
     TRUSTREC delrec;
-    int delrecidx;
+    int delrecidx=0;
     int newflag = 0;
     ulong newlid = 0;
     PKT_public_key *pk = m_alloc_clear( sizeof *pk );
@@ -2448,11 +2751,13 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                        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],
-                                _("public key lost") );
+                                _("Hmmm, public key lost?") );
+                 #endif
                    rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
                    if( revoke )
                        rec.r.sig.sig[i].flag |= SIGF_REVOKED;
@@ -2477,8 +2782,8 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                    && (!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 not yet marked.\n",
+                       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;
@@ -2491,7 +2796,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
                }
            }
            else {
-               log_error("sig record %lu[%d] points to wrong record.\n",
+               log_error(_("sig record %lu[%d] points to wrong record.\n"),
                            rec.r.sig.sig[i].lid, i );
                die_invalid_db();
            }
@@ -2634,9 +2939,18 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
     /* 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? */
+    /* And set the revocation flag into the dir record */
+    drec.r.dir.dirflags &= ~DIRF_REVOKED;
     lastrecno = 0;
     for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
        read_record( recno, &krec, RECTYPE_KEY );
+       if( recno == drec.r.dir.keylist ) { /* this is the primary key */
+           if( (krec.r.key.keyflags & KEYF_REVOKED) ) {
+               drec.r.dir.dirflags |= DIRF_REVOKED;
+               drec.dirty = 1;
+           }
+       }
+
        if( !qry_recno_list( recno_list, recno, RECTYPE_KEY ) ) {
            /* delete this one */
            if( !lastrecno ) {
@@ -2689,9 +3003,11 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
     if( rc )
        rc = tdbio_cancel_transaction();
     else {
-       write_record( &drec );
        if( modified && tdbio_is_dirty() )
            *modified = 1;
+       drec.r.dir.dirflags |= DIRF_CHECKED;
+       drec.r.dir.dirflags &= ~DIRF_VALVALID;
+       write_record( &drec );
        rc = tdbio_end_transaction();
     }
     rel_recno_list( &recno_list );
@@ -2733,7 +3049,7 @@ insert_trust_record( PKT_public_key *pk )
     /* 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",
+       log_error( _("insert_trust_record: keyblock not found: %s\n"),
                                                          g10_errstr(rc) );
        goto leave;
     }
@@ -2751,7 +3067,7 @@ insert_trust_record( PKT_public_key *pk )
        keyid_from_pk( pk, bkid );
 
        if( akid[0] != bkid[0] || akid[1] != bkid[1] ) {
-           log_error("did not use primary key for insert_trust_record()\n");
+           log_error(_("did not use primary key for insert_trust_record()\n"));
            rc = G10ERR_GENERAL;
            goto leave;
        }
@@ -2763,7 +3079,7 @@ insert_trust_record( PKT_public_key *pk )
      */
     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));
+       log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
        die_invalid_db();
     }
     memset( &dirrec, 0, sizeof dirrec );
@@ -2795,7 +3111,7 @@ insert_trust_record( PKT_public_key *pk )
     }
 
     /* and put all the other stuff into the keydb */
-    rc = update_trust_record( keyblock, 0, NULL );
+    rc = update_trust_record( keyblock, 1, NULL );
     if( !rc )
        process_hintlist( hintlist, dirrec.r.dir.lid );