]> granicus.if.org Git - mutt/commitdiff
Heavy hacking on mutt's pgp support. We no longer read the complete
authorThomas Roessler <roessler@does-not-exist.org>
Fri, 22 Jan 1999 15:24:58 +0000 (15:24 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Fri, 22 Jan 1999 15:24:58 +0000 (15:24 +0000)
key ring into memory.  For gpg, performance is heavily improved due
to the fact that we are passing a couple of key hints to the key
ring parsing back-end.

compose.c
gnupgparse.c
handler.c
lib.c
pgp.c
pgp.h
pgpkey.c
pgppubring.c
protos.h

index 402558110c7696fd12100dfa12051f9ebbc7db75..caa192dca5c40b95fc17f26ce99bfb5ff77fc8f0 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -127,11 +127,9 @@ static void redraw_pgp_lines (int pgp)
 
 static int pgp_send_menu (int bits, int *redraw)
 {
-  char *p;
-  char *micalg = NULL;
+  pgp_key_t *p;
   char input_signas[SHORT_STRING];
   char input_micalg[SHORT_STRING];
-  KEYINFO *secring;
 
   struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_SIGN);
 
@@ -147,39 +145,27 @@ static int pgp_send_menu (int bits, int *redraw)
     break;
 
   case 3: /* sign (a)s */
+
     unset_option(OPTPGPCHECKTRUST);
 
-    if(pgp)
+    if (pgp && (p = pgp_ask_for_key (pgp, _("Sign as: "), NULL, KEYFLAG_CANSIGN, PGP_PUBRING)))
     {
-      if(!(secring = pgp->read_secring(pgp)))
-      {
-       mutt_error _("Can't open your secret key ring!");
-       bits &= ~PGPSIGN;
-      }
-      else 
-      {
-       if ((p = pgp_ask_for_key (pgp, secring, _("Sign as: "), 
-                                 NULL, KEYFLAG_CANSIGN, &micalg)))
-       {
-         snprintf (input_signas, sizeof (input_signas), "0x%s", p);
-         safe_free((void **) &PgpSignAs);
-         PgpSignAs = safe_strdup(input_signas);
-         safe_free((void **) &PgpSignMicalg);
-         PgpSignMicalg = micalg;       /* micalg is malloc()ed by pgp_ask_for_key */
-         pgp_void_passphrase ();       /* probably need a different passphrase */
-         safe_free ((void **) &p);
-         bits |= PGPSIGN;
-       }
-
-       pgp_close_keydb(&secring);
-       *redraw = REDRAW_FULL;
-      }
+      snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p));
+      safe_free((void **) &PgpSignAs);             PgpSignAs = safe_strdup (input_signas);
+      safe_free((void **) &PgpSignMicalg);  PgpSignMicalg = safe_strdup (pgp_pkalg_to_mic (p->algorithm));
+      pgp_free_key (&p);
+      
+      bits |= PGPSIGN;
+       
+      pgp_void_passphrase ();  /* probably need a different passphrase */
     }
     else
     {
       bits &= ~PGPSIGN;
       mutt_error _("An unkown PGP version was defined for signing.");
     }
+
+    *redraw = REDRAW_FULL;
     break;
 
   case 4: /* (b)oth */
@@ -187,24 +173,24 @@ static int pgp_send_menu (int bits, int *redraw)
     break;
 
   case 5: /* select (m)ic algorithm */
-    if(!(bits & PGPSIGN))
+    if (!(bits & PGPSIGN))
       mutt_error _("This doesn't make sense if you don't want to sign the message.");
     else
     {
       /* Copy the existing MIC algorithm into place */
-      strfcpy(input_micalg, NONULL(PgpSignMicalg), sizeof(input_micalg));
+      strfcpy(input_micalg, NONULL (PgpSignMicalg), sizeof (input_micalg));
 
-      if(mutt_get_field (_("MIC algorithm: "), input_micalg, sizeof(input_micalg), 0) == 0)
+      if (mutt_get_field (_("MIC algorithm: "), input_micalg, sizeof (input_micalg), 0) == 0)
       {
-       if(mutt_strcasecmp(input_micalg, "pgp-md5") && mutt_strcasecmp(input_micalg, "pgp-sha1")
-          && mutt_strcasecmp(input_micalg, "pgp-rmd160"))
+       if (mutt_strcasecmp (input_micalg, "pgp-md5") && mutt_strcasecmp (input_micalg, "pgp-sha1")
+          && mutt_strcasecmp (input_micalg, "pgp-rmd160"))
        {
          mutt_error _("Unknown MIC algorithm, valid ones are: pgp-md5, pgp-sha1, pgp-rmd160");
        }
        else 
        {
-         safe_free((void **) &PgpSignMicalg);
-         PgpSignMicalg = safe_strdup(input_micalg);
+         safe_free ((void **) &PgpSignMicalg);
+         PgpSignMicalg = safe_strdup (input_micalg);
        }
       }
     }
index 306b6c879b16ab45101db769d9d216790e9c32b9..f62bb659455b73ae298b9a7c5e83bf83f1557228 100644 (file)
@@ -1,19 +1,23 @@
 /*
  * Copyright (C) 1998 Werner Koch <werner.koch@guug.de>
+ * Copyright (C) 1999 Thomas Roessler <roessler@guug.de>
  *
- *     This program 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.
+ *     This program 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.
  *
- *     This program 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.
+ *     This program is distributed in the hope that it will be
+ *     useful, but WITHOUT ANY WARRANTY; without even the implied
+ *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *     PURPOSE.  See the GNU General Public License for more
+ *     details.
  *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+ *     02139, USA.
  */
 
 
  *   - signature class
  */
 
-static KEYINFO *parse_pub_line( char *buf, int *is_subkey )
+static pgp_key_t *parse_pub_line (char *buf, int *is_subkey, pgp_key_t *k)
 {
-    KEYINFO *k=NULL;
-    PGPUID *uid = NULL;
-    int field = 0;
-    char *pend, *p;
-    int trust = 0;
-
-    *is_subkey = 0;
-    if( !*buf )
-       return NULL;
-    for( p = buf; p; p = pend ) {
-       if( (pend = strchr(p, ':')) )
-           *pend++ = 0;
-       field++;
-       if( field > 1 && !*p )
-           continue;
-
-       switch( field ) {
-         case 1: /* record type */
-           if( !mutt_strcmp(p,"pub") )
-               ;
-           else if( !mutt_strcmp(p,"sub") )
-               *is_subkey = 1;
-           else if( !mutt_strcmp(p,"sec") )
-               ;
-           else if( !mutt_strcmp(p,"ssb") )
-               *is_subkey = 1;
-           else
-               return NULL;
-           k = safe_malloc( sizeof(KEYINFO) );
-           memset(k, 0, sizeof(KEYINFO) );
-           break;
-         case 2: /* trust info */
-           switch( *p ) { /* look only at the first letter */
-             case 'e': k->flags |= KEYFLAG_EXPIRED;   break;
-             case 'n': trust = 1;  break;
-             case 'm': trust = 2;  break;
-             case 'f': trust = 3;  break;
-             case 'u': trust = 3;  break;
-             case 'r': k->flags |= KEYFLAG_REVOKED;   break;
-           }
-           break;
-         case 3: /* key length  */
-           k->keylen = atoi(p); /* fixme: add validation checks */
-           break;
-         case 4: /* pubkey algo */
-           k->algorithm = pgp_pkalgbytype(atoi(p));
-           k->flags |= pgp_get_abilities(atoi(p));
-           break;
-         case 5: /* 16 hex digits with the long keyid. */
-           /* We really should do a check here */
-           k->keyid = safe_strdup(p);
-           break;
-         case 6: /* timestamp (1998-02-28) */
-           break;
-         case 7: /* valid for n days */
+  pgp_uid_t *uid = NULL;
+  int field = 0, is_uid = 0;
+  char *pend, *p;
+  int trust = 0;
+
+  *is_subkey = 0;
+  if (!*buf)
+    return NULL;
+  for (p = buf; p; p = pend)
+  {
+    if ((pend = strchr (p, ':')))
+      *pend++ = 0;
+    field++;
+    if (field > 1 && !*p)
+      continue;
+
+    switch (field)
+    {
+      case 1:                  /* record type */
+      {
+       if (!mutt_strcmp (p, "pub"))
+         ;
+       else if (!mutt_strcmp (p, "sub"))
+         *is_subkey = 1;
+       else if (!mutt_strcmp (p, "sec"))
+         ;
+       else if (!mutt_strcmp (p, "ssb"))
+         *is_subkey = 1;
+       else if (!mutt_strcmp (p, "uid"))
+         is_uid = 1;
+       else
+         return NULL;
+       
+       if (!is_uid)
+         k = safe_calloc (sizeof (pgp_key_t), 1);
+
+       break;
+      }
+      case 2:                  /* trust info */
+      /*
+       * XXX - is this the owner-trust field?
+       *
+       * Actually, we'd need the trust gpg has into the 
+       * association between a user ID and a key.
+       * 
+       * - tlr
+       */
+      {
+       switch (*p)
+       {                               /* look only at the first letter */
+         case 'e':
+           k->flags |= KEYFLAG_EXPIRED;
            break;
-         case 8: /* Local id         */
+         case 'n':
+           trust = 1;
            break;
-         case 9: /* ownertrust       */
+         case 'm':
+           trust = 2;
            break;
-         case 10: /* name             */
-           if( !pend || !*p )
-               break; /* empty field or no trailing colon */
-           k->address = mutt_new_list();
-           k->address->data = safe_malloc( sizeof(PGPUID) );
-           uid = (PGPUID *)k->address->data;
-           uid->addr = safe_strdup(p);
-           uid->trust = trust;
+         case 'f':
+           trust = 3;
            break;
-         case 11: /* signature class  */
+         case 'u':
+           trust = 3;
            break;
-         default:
+         case 'r':
+           k->flags |= KEYFLAG_REVOKED;
            break;
        }
+       break;
+      }
+      case 3:                  /* key length  */
+      {
+       k->keylen = atoi (p);   /* fixme: add validation checks */
+       break;
+      }
+      case 4:                  /* pubkey algo */
+      {
+       k->algorithm = pgp_pkalgbytype (atoi (p));
+       k->flags |= pgp_get_abilities (atoi (p));
+       break;
+      }
+      case 5:                  /* 16 hex digits with the long keyid. */
+      {
+       /* We really should do a check here */
+       k->keyid = safe_strdup (p);
+       break;
+
+      }
+      case 6:                  /* timestamp (1998-02-28) */
+        break;
+      case 7:                  /* valid for n days */
+        break;
+      case 8:                  /* Local id         */
+        break;
+      case 9:                  /* ownertrust       */
+        break;
+      case 10:                 /* name             */
+      {
+       if (!pend || !*p)
+         break;                        /* empty field or no trailing colon */
+       uid = safe_calloc (sizeof (pgp_uid_t), 1);
+       uid->addr = safe_strdup (p);
+       uid->trust = trust;
+       uid->parent = k;
+       uid->next = k->address;
+       k->address = uid;
+       
+       if (strstr (p, "ENCR"))
+         k->flags |= KEYFLAG_PREFER_ENCRYPTION;
+       if (strstr (p, "SIGN"))
+         k->flags |= KEYFLAG_PREFER_SIGNING;
+
+       break;
+      }
+      case 11:                 /* signature class  */
+        break;
+      default:
+        break;
     }
-    return k;
+  }
+  return k;
 }
 
-static pid_t gpg_invoke_list_keys(struct pgp_vinfo *pgp,
-                                 FILE **pgpin, FILE **pgpout, FILE **pgperr,
-                                 int pgpinfd, int pgpoutfd, int pgperrfd,
-                                 const char *uids, int secret)
+static pid_t gpg_invoke_list_keys (struct pgp_vinfo *pgp,
+                             FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
+                                  int pgpinfd, int pgpoutfd, int pgperrfd,
+                                  pgp_ring_t keyring,
+                                  LIST * hints)
 {
   char cmd[HUGE_STRING];
   char tmpcmd[HUGE_STRING];
-  char *cp;
-  char *keylist;
-  
+
   /* we use gpgm here */
-  snprintf(cmd, sizeof(cmd),
-          "%sm --no-verbose --batch --with-colons --list-%skeys ",
-          NONULL(*pgp->binary), secret? "secret-":"");
+  snprintf (cmd, sizeof (cmd),
+           "%sm --no-verbose --batch --with-colons --list-%skeys ",
+           NONULL (*pgp->binary), keyring == PGP_SECRING ? "secret-" : "");
 
-  keylist = safe_strdup(uids);
-  for(cp = strtok(keylist, " "); cp ; cp = strtok(NULL, " "))
+  for (; hints; hints = hints->next)
   {
-    snprintf(tmpcmd, sizeof(tmpcmd), "%s %s",
-            cmd, cp);
-    strcpy(cmd, tmpcmd);
+    snprintf (tmpcmd, sizeof (tmpcmd), "%s %s", cmd, (char *) hints->data);
+    strcpy (cmd, tmpcmd);
   }
-  safe_free((void **) &keylist);
-  return mutt_create_filter_fd(cmd, pgpin, pgpout, pgperr,
-                              pgpinfd, pgpoutfd, pgperrfd);
+
+  return mutt_create_filter_fd (cmd, pgpin, pgpout, pgperr,
+                               pgpinfd, pgpoutfd, pgperrfd);
 }
 
-static KEYINFO *read_ring(struct pgp_vinfo *pgp, int secret )
+pgp_key_t *gpg_get_candidates (struct pgp_vinfo * pgp, pgp_ring_t keyring,
+                              LIST * hints)
 {
-    FILE *fp;
-    pid_t thepid;
-    char buf[LONG_STRING];
-    KEYINFO *db = NULL, **kend, *k = NULL, *kk, *mainkey=NULL;
-    int is_sub;
-    int devnull;
-  
-    if((devnull = open("/dev/null", O_RDWR)) == -1)
-        return NULL;
-  
-    thepid = gpg_invoke_list_keys(pgp, NULL, &fp, NULL, -1, -1, devnull,
-                                                       NULL, secret);
-    if( thepid == -1 )
-    {
-        close(devnull);
-       return NULL;
-    }
+  FILE *fp;
+  pid_t thepid;
+  char buf[LONG_STRING];
+  pgp_key_t *db = NULL, **kend, *k = NULL, *kk, *mainkey = NULL;
+  int is_sub;
+  int devnull;
 
-    kend = &db;
-    k = NULL;
-    while( fgets( buf, sizeof(buf)-1, fp ) ) {
-       kk = parse_pub_line(buf, &is_sub );
-       if( !kk )
-           continue;
-       if( k )
-           kend = &k->next;
-       *kend = k = kk;
-
-       if( is_sub ) {
-           k->flags |= KEYFLAG_SUBKEY;
-           k->mainkey = mainkey;
-    }
-       else
-           mainkey = k;
-    }
-    if( ferror(fp) )
-       mutt_perror("fgets");
+  if ((devnull = open ("/dev/null", O_RDWR)) == -1)
+    return NULL;
 
-    fclose( fp );
-    mutt_wait_filter( thepid );
+  thepid = gpg_invoke_list_keys (pgp, NULL, &fp, NULL, -1, -1, devnull,
+                                keyring, hints);
+  if (thepid == -1)
+  {
+    close (devnull);
+    return NULL;
+  }
 
-    close(devnull);
-  
-    return db;
-}
+  kend = &db;
+  k = NULL;
+  while (fgets (buf, sizeof (buf) - 1, fp))
+  {
+    kk = parse_pub_line (buf, &is_sub, k);
+    if (!kk)
+      continue;
 
+    /* Only append kk to the list if it's new. */
+    if (kk != k)
+    {
+      if (k)
+       kend = &k->next;
+      *kend = k = kk;
+      
+      if (is_sub)
+      {
+       k->flags |= KEYFLAG_SUBKEY;
+       k->parent = mainkey;
+      }
+      else
+       mainkey = k;
+    }
+  }
+  if (ferror (fp))
+    mutt_perror ("fgets");
 
-KEYINFO *gpg_read_pubring(struct pgp_vinfo *pgp)
-{
-    return read_ring( pgp, 0 );
-}
+  fclose (fp);
+  mutt_wait_filter (thepid);
 
+  close (devnull);
 
-KEYINFO *gpg_read_secring(struct pgp_vinfo *pgp)
-{
-    return read_ring( pgp, 1 );
+  return db;
 }
+
index 20d46e08ec2b9ba1cc706d7d70751f1ba5ad452b..ba1bc99196e6001847a333d3237a4adccbe878d7 100644 (file)
--- a/handler.c
+++ b/handler.c
@@ -1406,7 +1406,7 @@ void mutt_body_handler (BODY *b, STATE *s)
   else if (b->type == TYPEAPPLICATION)
   {
     if (mutt_is_application_pgp(b))
-      handler = application_pgp_handler;
+      handler = pgp_application_pgp_handler;
   }
 #endif /* _PGPPATH */
 
diff --git a/lib.c b/lib.c
index 4653e97727b77ead46f4972fba8413309109ebee..5466d79d05a74b7760f0406f9ce76ffe0bb08a06 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -1314,3 +1314,23 @@ size_t mutt_strlen(const char *a)
 {
   return a ? strlen (a) : 0;
 }
+
+const char *mutt_stristr (const char *haystack, const char *needle)
+{
+  const char *p, *q;
+
+  if (!haystack)
+    return NULL;
+  if (!needle)
+    return (haystack);
+
+  while (*(p = haystack))
+  {
+    for (q = needle; *p && *q && tolower (*p) == tolower (*q); p++, q++)
+      ;
+    if (!*q)
+      return (haystack);
+    haystack++;
+  }
+  return NULL;
+}
diff --git a/pgp.c b/pgp.c
index 4ec0dae1b37151ff0c91c2ae15c98156a8677b82..375cb6a2a24de0c49b0cef0676ee9096d47a3c4b 100644 (file)
--- a/pgp.c
+++ b/pgp.c
@@ -51,7 +51,7 @@ static struct pgp_vinfo pgp_vinfo[] =
   { PGP_V2,    
     "pgp2",    
     &PgpV2,    &PgpV2Pubring,  &PgpV2Secring,  &PgpV2Language, 
-    pgp_read_pubring, pgp_read_secring,
+    pgp_get_candidates,
     pgp_v2_invoke_decode, pgp_v2_invoke_verify, pgp_v2_invoke_decrypt,
     pgp_v2_invoke_sign, pgp_v2_invoke_encrypt, pgp_v2_invoke_import,
     pgp_v2_invoke_export, pgp_v2_invoke_verify_key 
@@ -60,7 +60,7 @@ static struct pgp_vinfo pgp_vinfo[] =
   { PGP_V3,    
     "pgp3",    
     &PgpV3,    &PgpV3Pubring,  &PgpV3Secring,  &PgpV3Language, 
-    pgp_read_pubring, pgp_read_secring,
+    pgp_get_candidates,
     pgp_v3_invoke_decode, pgp_v3_invoke_verify, pgp_v3_invoke_decrypt,
     pgp_v3_invoke_sign, pgp_v3_invoke_encrypt, pgp_v3_invoke_import,
     pgp_v3_invoke_export, pgp_v3_invoke_verify_key 
@@ -69,7 +69,7 @@ static struct pgp_vinfo pgp_vinfo[] =
   { PGP_V3,    
     "pgp5",    
     &PgpV3,    &PgpV3Pubring,  &PgpV3Secring,  &PgpV3Language, 
-    pgp_read_pubring, pgp_read_secring,
+    pgp_get_candidates,
     pgp_v3_invoke_decode, pgp_v3_invoke_verify, pgp_v3_invoke_decrypt,
     pgp_v3_invoke_sign, pgp_v3_invoke_encrypt, pgp_v3_invoke_import,
     pgp_v3_invoke_export, pgp_v3_invoke_verify_key 
@@ -78,7 +78,7 @@ static struct pgp_vinfo pgp_vinfo[] =
   { PGP_GPG,   
     "gpg",     
     &PgpGpg,   &PgpGpgDummy,   &PgpGpgDummy, &PgpGpgDummy,
-    gpg_read_pubring, gpg_read_secring,
+    gpg_get_candidates,
     pgp_gpg_invoke_decode, pgp_gpg_invoke_verify, pgp_gpg_invoke_decrypt,
     pgp_gpg_invoke_sign, pgp_gpg_invoke_encrypt, pgp_gpg_invoke_import,
     pgp_gpg_invoke_export, pgp_gpg_invoke_verify_key 
@@ -178,15 +178,15 @@ struct pgp_vinfo *pgp_get_vinfo(enum pgp_ops op)
   return NULL;
 }
 
-char *pgp_keyid(KEYINFO *k)
+char *pgp_keyid(pgp_key_t *k)
 {
-  if((k->flags & KEYFLAG_SUBKEY) && k->mainkey)
-    k = k->mainkey;
+  if((k->flags & KEYFLAG_SUBKEY) && k->parent)
+    k = k->parent;
 
   return _pgp_keyid(k);
 }
 
-char *_pgp_keyid(KEYINFO *k)
+char *_pgp_keyid(pgp_key_t *k)
 {
   if(option(OPTPGPLONGIDS))
     return k->keyid;
@@ -217,7 +217,7 @@ static void pgp_current_time (STATE *s)
 
 /* Support for the Application/PGP Content Type. */
 
-void application_pgp_handler (BODY *m, STATE *s)
+void pgp_application_pgp_handler (BODY *m, STATE *s)
 {
   int needpass = -1, pgp_keyblock = 0;
   int clearsign = 0;
@@ -1231,22 +1231,19 @@ static BODY *pgp_sign_message (BODY *a)
  */
 char *pgp_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
 {
-  char *key, *keyID, *keylist = NULL;
+  char *keyID, *keylist = NULL;
   size_t keylist_size = 0;
   size_t keylist_used = 0;
   ADDRESS *tmp = NULL;
   ADDRESS **last = &tmp;
   ADDRESS *p;
   int i;
-  KEYINFO *db;
-  KEYINFO *k_info;
-  struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_ENCRYPT);
+  pgp_key_t *k_info, *key;
+  struct pgp_vinfo *pgp = pgp_get_vinfo (PGP_ENCRYPT);
   
-  if(!pgp)
+  if (!pgp)
     return NULL;
   
-  db = pgp->read_pubring(pgp);
-
   for (i = 0; i < 3; i++) 
   {
     switch (i)
@@ -1273,32 +1270,34 @@ char *pgp_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
     {
       snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID, p->mailbox);
       if (mutt_yesorno (buf, M_YES) == M_YES)
-       k_info = ki_getkeybystr (pgp, keyID, db, KEYFLAG_CANENCRYPT);
+       k_info = pgp_getkeybystr (pgp, keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
     }
-    if (k_info == NULL && (k_info = ki_getkeybyaddr (pgp, p, db, KEYFLAG_CANENCRYPT)) == NULL)
+
+    if (k_info == NULL && (k_info = pgp_getkeybyaddr (pgp, p, KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL)
     {
       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), p->mailbox);
       
-      if ((key = pgp_ask_for_key (pgp, db, buf, p->mailbox,
-                                 KEYFLAG_CANENCRYPT, NULL)) == NULL)
+      if ((key = pgp_ask_for_key (pgp, buf, p->mailbox,
+                                 KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL)
       {
-       pgp_close_keydb (&db);
        safe_free ((void **)&keylist);
        rfc822_free_address (&tmp);
        return NULL;
       }
     }
     else
-      key = pgp_keyid(k_info);
+      key = k_info;
 
-    keylist_size += mutt_strlen (key) + 4;
+    keyID = pgp_keyid (key);
+    pgp_free_key (&key);
+    
+    keylist_size += mutt_strlen (keyID) + 4;
     safe_realloc ((void **)&keylist, keylist_size);
     sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "",
-            key);
+            keyID);
     keylist_used = mutt_strlen (keylist);
   }
   rfc822_free_address (&tmp);
-  pgp_close_keydb (&db);
   return (keylist);
 }
 
diff --git a/pgp.h b/pgp.h
index 7438484591f1906704048ade7447f3a07d8b733f..24490903415a8345d836d1cdad4691897a08b11e 100644 (file)
--- a/pgp.h
+++ b/pgp.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
- * 
+ * Copyright (C) 1999 Thoms Roessler <roessler@guug.de>
+ *
  *     This program 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
@@ -14,7 +15,7 @@
  *     You should have received a copy of the GNU General Public License
  *     along with this program; if not, write to the Free Software
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */ 
+ */
 
 #ifdef _PGPPATH
 
 #define KEYFLAG_PREFER_ENCRYPTION (1 << 13)
 #define KEYFLAG_PREFER_SIGNING (1 << 14)
 
-typedef struct keyinfo
+#define KEYFLAG_CANTUSE (KEYFLAG_DISABLED|KEYFLAG_REVOKED|KEYFLAG_EXPIRED)
+
+typedef struct pgp_keyinfo
 {
   char *keyid;
-  LIST *address;
+  struct pgp_uid *address;
   short flags;
   short keylen;
   unsigned long gen_time;
   const char *algorithm;
-  struct keyinfo *mainkey;
-  struct keyinfo *next;
-} KEYINFO;
+  struct pgp_keyinfo *parent;
+  struct pgp_keyinfo *next;
+}
+pgp_key_t;
 
 typedef struct pgp_uid
 {
   char *addr;
   short trust;
-} PGPUID;
+  struct pgp_keyinfo *parent;
+  struct pgp_uid *next;
+}
+pgp_uid_t;
 
-enum pgp_version 
+enum pgp_version
 {
-  PGP_V2, 
+  PGP_V2,
   PGP_V3,
   PGP_GPG,
   PGP_UNKNOWN
 };
 
+enum pgp_ring
+{
+  PGP_PUBRING,
+  PGP_SECRING
+};
+
+typedef enum pgp_ring pgp_ring_t;
+
 enum pgp_ops
 {
-  PGP_DECODE,          /* application/pgp */
-  PGP_VERIFY,          /* PGP/MIME, signed */
-  PGP_DECRYPT,         /* PGP/MIME, encrypted */
-  PGP_SIGN,            /* sign data */
-  PGP_ENCRYPT,         /* encrypt data */
-  PGP_IMPORT,          /* extract keys from messages */
-  PGP_VERIFY_KEY,      /* verify key when selecting */
-  PGP_EXPORT,          /* extract keys from key ring */
+  PGP_DECODE,                  /* application/pgp */
+  PGP_VERIFY,                  /* PGP/MIME, signed */
+  PGP_DECRYPT,                 /* PGP/MIME, encrypted */
+  PGP_SIGN,                    /* sign data */
+  PGP_ENCRYPT,                 /* encrypt data */
+  PGP_IMPORT,                  /* extract keys from messages */
+  PGP_VERIFY_KEY,              /* verify key when selecting */
+  PGP_EXPORT,                  /* extract keys from key ring */
   PGP_LAST_OP
 };
 
 struct pgp_vinfo
 {
-  
+
   /* data */
-  
+
   enum pgp_version v;
   char *name;
   char **binary;
   char **pubring;
   char **secring;
   char **language;
-  
+
   /* functions */
+
+  pgp_key_t *(*get_candidates) (struct pgp_vinfo *, pgp_ring_t, LIST *);
   
-  KEYINFO * (*read_pubring)(struct pgp_vinfo *);
-  KEYINFO * (*read_secring)(struct pgp_vinfo *);
-  
-  pid_t (*invoke_decode)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
-                     int, int, int,
-                     const char *, int);
+  pid_t (*invoke_decode) (struct pgp_vinfo *, FILE **, FILE **, FILE **,
+                         int, int, int,
+                         const char *, int);
   
-  pid_t (*invoke_verify)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
-                     int, int, int,
-                     const char *, const char *);
+  pid_t (*invoke_verify) (struct pgp_vinfo *, FILE **, FILE **, FILE **,
+                         int, int, int,
+                         const char *, const char *);
   
-  pid_t (*invoke_decrypt)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
-                      int, int, int,
-                      const char *);
+  pid_t (*invoke_decrypt) (struct pgp_vinfo *, FILE **, FILE **, FILE **,
+                          int, int, int,
+                          const char *);
   
-  pid_t (*invoke_sign)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
-                   int, int, int,
-                   const char *);
-
-  pid_t (*invoke_encrypt)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
-                      int, int, int,
-                      const char *, const char *, int);
+  pid_t (*invoke_sign) (struct pgp_vinfo *, FILE **, FILE **, FILE **,
+                       int, int, int,
+                       const char *);
   
-  void (*invoke_import)(struct pgp_vinfo *, const char *);
+  pid_t (*invoke_encrypt) (struct pgp_vinfo *, FILE **, FILE **, FILE **,
+                          int, int, int,
+                          const char *, const char *, int);
   
-  pid_t (*invoke_export)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
-                     int, int, int,
-                     const char *);
+  void (*invoke_import) (struct pgp_vinfo *, const char *);
   
-  pid_t (*invoke_verify_key)(struct pgp_vinfo *, FILE **, FILE **, FILE **,
+  pid_t (*invoke_export) (struct pgp_vinfo *, FILE **, FILE **, FILE **,
                          int, int, int,
                          const char *);
   
+  pid_t (*invoke_verify_key) (struct pgp_vinfo *, FILE **, FILE **, FILE **,
+                             int, int, int,
+                             const char *);
+  
 };
 
 
@@ -150,176 +164,172 @@ WHERE char *PgpSignMicalg;
 
 WHERE short PgpTimeout;
 
-
-
 BODY *pgp_decrypt_part (BODY *, STATE *, FILE *);
 BODY *pgp_make_key_attachment (char *);
 
-const char *pgp_pkalg_to_mic(const char *);
-
-char *pgp_ask_for_key (struct pgp_vinfo *, KEYINFO *, char *, char *, short, char **);
-char *pgp_keyid(KEYINFO *);
-char *_pgp_keyid(KEYINFO *);
+char *_pgp_keyid (pgp_key_t *);
+char *pgp_keyid (pgp_key_t *);
 
-struct pgp_vinfo *pgp_get_vinfo(enum pgp_ops);
+const char *pgp_pkalg_to_mic (const char *);
+const char *pgp_pkalgbytype (unsigned char);
 
-int mutt_check_pgp (HEADER *h);
+int mutt_check_pgp (HEADER * h);
+int mutt_is_application_pgp (BODY *);
+int mutt_is_multipart_encrypted (BODY *);
+int mutt_is_multipart_signed (BODY *);
 int mutt_parse_pgp_hdr (char *, int);
-
-int mutt_is_multipart_encrypted(BODY *);
-int mutt_is_multipart_signed(BODY *);
-int mutt_is_application_pgp(BODY *);
-
 int pgp_decrypt_mime (FILE *, FILE **, BODY *, BODY **);
 int pgp_get_keys (HEADER *, char **);
 int pgp_protect (HEADER *, char *);
 int pgp_query (BODY *);
+int pgp_string_matches_hint (const char *s, LIST * hints);
 int pgp_valid_passphrase (void);
 
-KEYINFO *ki_getkeybyaddr (struct pgp_vinfo *pgp, ADDRESS *, KEYINFO *, short);
-KEYINFO *ki_getkeybystr (struct pgp_vinfo *pgp, char *, KEYINFO *, short);
-KEYINFO *pgp_read_pubring(struct pgp_vinfo *pgp);
-KEYINFO *pgp_read_secring(struct pgp_vinfo *pgp);
-KEYINFO *gpg_read_pubring(struct pgp_vinfo *pgp);
-KEYINFO *gpg_read_secring(struct pgp_vinfo *pgp);
+pgp_key_t *gpg_get_candidates (struct pgp_vinfo *, pgp_ring_t, LIST *);
+pgp_key_t *pgp_ask_for_key (struct pgp_vinfo *, char *, char *, short, pgp_ring_t);
+pgp_key_t *pgp_get_candidates (struct pgp_vinfo *, pgp_ring_t, LIST *);
+pgp_key_t *pgp_getkeybyaddr (struct pgp_vinfo *pgp, ADDRESS *, short, pgp_ring_t);
+pgp_key_t *pgp_getkeybystr (struct pgp_vinfo *pgp, char *, short, pgp_ring_t);
+pgp_key_t *pgp_remove_key (pgp_key_t **, pgp_key_t *);
+
+short pgp_canencrypt (unsigned char);
+short pgp_cansign (unsigned char);
+short pgp_get_abilities (unsigned char);
+
+struct pgp_vinfo *pgp_get_vinfo (enum pgp_ops);
 
-void application_pgp_handler (BODY *, STATE *);
 void mutt_forget_passphrase (void);
-void pgp_close_keydb (KEYINFO **);
+void pgp_application_pgp_handler (BODY *, STATE *);
 void pgp_encrypted_handler (BODY *, STATE *);
-void pgp_extract_keys_from_attachment_list (FILE *fp, int tag, BODY *top);
-void pgp_extract_keys_from_messages(HEADER *hdr);
+void pgp_extract_keys_from_attachment_list (FILE * fp, int tag, BODY * top);
+void pgp_extract_keys_from_messages (HEADER * hdr);
+void pgp_free_key (pgp_key_t **kpp);
 void pgp_signed_handler (BODY *, STATE *);
 void pgp_void_passphrase (void);
 
-short pgp_canencrypt(unsigned char);
-short pgp_cansign(unsigned char);
-short pgp_get_abilities(unsigned char);
-const char *pgp_pkalgbytype(unsigned char);
-
 #define pgp_secring(a) pgp_getring(a, 0)
 #define pgp_pubring(a) pgp_getring(a, 1)
 
 /* PGP V2 prototypes */
 
 
-pid_t pgp_v2_invoke_decode(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, int);
+pid_t pgp_v2_invoke_decode (struct pgp_vinfo *,
+                           FILE **, FILE **, FILE **,
+                           int, int, int,
+                           const char *, int);
 
-pid_t pgp_v2_invoke_verify(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, const char *);
+pid_t pgp_v2_invoke_verify (struct pgp_vinfo *,
+                           FILE **, FILE **, FILE **,
+                           int, int, int,
+                           const char *, const char *);
 
 
-pid_t pgp_v2_invoke_decrypt(struct pgp_vinfo *,
-                                FILE **, FILE **, FILE **,
-                                int, int, int,
-                                const char *);
+pid_t pgp_v2_invoke_decrypt (struct pgp_vinfo *,
+                            FILE **, FILE **, FILE **,
+                            int, int, int,
+                            const char *);
 
-pid_t pgp_v2_invoke_sign(struct pgp_vinfo *, 
-                             FILE **, FILE **, FILE **,
-                             int, int, int,
-                             const char *);
+pid_t pgp_v2_invoke_sign (struct pgp_vinfo *,
+                         FILE **, FILE **, FILE **,
+                         int, int, int,
+                         const char *);
 
-pid_t pgp_v2_invoke_encrypt(struct pgp_vinfo *,
-                                FILE **, FILE **, FILE **,
-                                int, int, int,
-                                const char *, const char *, int);
+pid_t pgp_v2_invoke_encrypt (struct pgp_vinfo *,
+                            FILE **, FILE **, FILE **,
+                            int, int, int,
+                            const char *, const char *, int);
 
-void pgp_v2_invoke_import(struct pgp_vinfo *, const char *);
+void pgp_v2_invoke_import (struct pgp_vinfo *, const char *);
 
-pid_t pgp_v2_invoke_export(struct pgp_vinfo*, 
+pid_t pgp_v2_invoke_export (struct pgp_vinfo *,
+                           FILE **, FILE **, FILE **,
+                           int, int, int,
+                           const char *);
+
+pid_t pgp_v2_invoke_verify_key (struct pgp_vinfo *,
                                FILE **, FILE **, FILE **,
                                int, int, int,
                                const char *);
 
-pid_t pgp_v2_invoke_verify_key(struct pgp_vinfo *,
-                                   FILE **, FILE **, FILE **,
-                                   int, int, int,
-                                   const char *);
-
 /* PGP V3 prototypes */
 
-pid_t pgp_v3_invoke_decode(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, int);
+pid_t pgp_v3_invoke_decode (struct pgp_vinfo *,
+                           FILE **, FILE **, FILE **,
+                           int, int, int,
+                           const char *, int);
 
-pid_t pgp_v3_invoke_verify(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, const char *);
+pid_t pgp_v3_invoke_verify (struct pgp_vinfo *,
+                           FILE **, FILE **, FILE **,
+                           int, int, int,
+                           const char *, const char *);
 
 
-pid_t pgp_v3_invoke_decrypt(struct pgp_vinfo *,
-                                FILE **, FILE **, FILE **,
-                                int, int, int,
-                                const char *);
+pid_t pgp_v3_invoke_decrypt (struct pgp_vinfo *,
+                            FILE **, FILE **, FILE **,
+                            int, int, int,
+                            const char *);
 
-pid_t pgp_v3_invoke_sign(struct pgp_vinfo *, 
-                             FILE **, FILE **, FILE **,
-                             int, int, int,
-                             const char *);
+pid_t pgp_v3_invoke_sign (struct pgp_vinfo *,
+                         FILE **, FILE **, FILE **,
+                         int, int, int,
+                         const char *);
 
-pid_t pgp_v3_invoke_encrypt(struct pgp_vinfo *,
-                                FILE **, FILE **, FILE **,
-                                int, int, int,
-                                const char *, const char *, int);
+pid_t pgp_v3_invoke_encrypt (struct pgp_vinfo *,
+                            FILE **, FILE **, FILE **,
+                            int, int, int,
+                            const char *, const char *, int);
 
-void pgp_v3_invoke_import(struct pgp_vinfo *, const char *);
+void pgp_v3_invoke_import (struct pgp_vinfo *, const char *);
 
-pid_t pgp_v3_invoke_export(struct pgp_vinfo*, 
+pid_t pgp_v3_invoke_export (struct pgp_vinfo *,
+                           FILE **, FILE **, FILE **,
+                           int, int, int,
+                           const char *);
+
+pid_t pgp_v3_invoke_verify_key (struct pgp_vinfo *,
                                FILE **, FILE **, FILE **,
                                int, int, int,
                                const char *);
 
-pid_t pgp_v3_invoke_verify_key(struct pgp_vinfo *,
-                                   FILE **, FILE **, FILE **,
-                                   int, int, int,
-                                   const char *);
-
 /* GNU Privacy Guard Prototypes */
 
-pid_t pgp_gpg_invoke_decode(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, int);
+pid_t pgp_gpg_invoke_decode (struct pgp_vinfo *,
+                            FILE **, FILE **, FILE **,
+                            int, int, int,
+                            const char *, int);
 
-pid_t pgp_gpg_invoke_verify(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, const char *);
+pid_t pgp_gpg_invoke_verify (struct pgp_vinfo *,
+                            FILE **, FILE **, FILE **,
+                            int, int, int,
+                            const char *, const char *);
 
 
-pid_t pgp_gpg_invoke_decrypt(struct pgp_vinfo *,
-                                FILE **, FILE **, FILE **,
-                                int, int, int,
-                                const char *);
-
-pid_t pgp_gpg_invoke_sign(struct pgp_vinfo *, 
+pid_t pgp_gpg_invoke_decrypt (struct pgp_vinfo *,
                              FILE **, FILE **, FILE **,
                              int, int, int,
                              const char *);
 
-pid_t pgp_gpg_invoke_encrypt(struct pgp_vinfo *,
-                                FILE **, FILE **, FILE **,
-                                int, int, int,
-                                const char *, const char *, int);
+pid_t pgp_gpg_invoke_sign (struct pgp_vinfo *,
+                          FILE **, FILE **, FILE **,
+                          int, int, int,
+                          const char *);
 
-void pgp_gpg_invoke_import(struct pgp_vinfo *, const char *);
+pid_t pgp_gpg_invoke_encrypt (struct pgp_vinfo *,
+                             FILE **, FILE **, FILE **,
+                             int, int, int,
+                             const char *, const char *, int);
 
-pid_t pgp_gpg_invoke_export(struct pgp_vinfo*, 
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *);
+void pgp_gpg_invoke_import (struct pgp_vinfo *, const char *);
+
+pid_t pgp_gpg_invoke_export (struct pgp_vinfo *,
+                            FILE **, FILE **, FILE **,
+                            int, int, int,
+                            const char *);
 
-pid_t pgp_gpg_invoke_verify_key(struct pgp_vinfo *,
-                                   FILE **, FILE **, FILE **,
-                                   int, int, int,
-                                   const char *);
+pid_t pgp_gpg_invoke_verify_key (struct pgp_vinfo *,
+                                FILE **, FILE **, FILE **,
+                                int, int, int,
+                                const char *);
 
 
 
@@ -329,43 +339,43 @@ pid_t pgp_gpg_invoke_verify_key(struct pgp_vinfo *,
 /* use these as templates for your own prototypes */
 
 
-pid_t pgp_VERSION_invoke_decode(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, int);
-
-pid_t pgp_VERSION_invoke_verify(struct pgp_vinfo *,
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *, const char *);
-
-
-pid_t pgp_VERSION_invoke_decrypt(struct pgp_vinfo *,
+pid_t pgp_VERSION_invoke_decode (struct pgp_vinfo *,
                                 FILE **, FILE **, FILE **,
                                 int, int, int,
-                                const char *);
+                                const char *, int);
 
-pid_t pgp_VERSION_invoke_sign(struct pgp_vinfo *, 
-                             FILE **, FILE **, FILE **,
-                             int, int, int,
-                             const char *);
-
-pid_t pgp_VERSION_invoke_encrypt(struct pgp_vinfo *,
+pid_t pgp_VERSION_invoke_verify (struct pgp_vinfo *,
                                 FILE **, FILE **, FILE **,
                                 int, int, int,
-                                const char *, const char *, int);
+                                const char *, const char *);
 
-void pgp_VERSION_invoke_import(struct pgp_vinfo *, const char *);
 
-pid_t pgp_VERSION_invoke_export(struct pgp_vinfo*, 
-                               FILE **, FILE **, FILE **,
-                               int, int, int,
-                               const char *);
+pid_t pgp_VERSION_invoke_decrypt (struct pgp_vinfo *,
+                                 FILE **, FILE **, FILE **,
+                                 int, int, int,
+                                 const char *);
+
+pid_t pgp_VERSION_invoke_sign (struct pgp_vinfo *,
+                              FILE **, FILE **, FILE **,
+                              int, int, int,
+                              const char *);
+
+pid_t pgp_VERSION_invoke_encrypt (struct pgp_vinfo *,
+                                 FILE **, FILE **, FILE **,
+                                 int, int, int,
+                                 const char *, const char *, int);
+
+void pgp_VERSION_invoke_import (struct pgp_vinfo *, const char *);
+
+pid_t pgp_VERSION_invoke_export (struct pgp_vinfo *,
+                                FILE **, FILE **, FILE **,
+                                int, int, int,
+                                const char *);
 
-pid_t pgp_VERSION_invoke_verify_key(struct pgp_vinfo *,
-                                   FILE **, FILE **, FILE **,
-                                   int, int, int,
-                                   const char *);
+pid_t pgp_VERSION_invoke_verify_key (struct pgp_vinfo *,
+                                    FILE **, FILE **, FILE **,
+                                    int, int, int,
+                                    const char *);
 
 #endif
 
index 281c956eab519803fa2bd3ba40bf20a379b5c101..62890f97b7d8260469d73264e216c65468bce287 100644 (file)
--- a/pgpkey.c
+++ b/pgpkey.c
@@ -15,7 +15,7 @@
  *     You should have received a copy of the GNU General Public License
  *     along with this program; if not, write to the Free Software
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */ 
+ */
 
 #include "mutt.h"
 #include "mutt_curses.h"
 
 #ifdef _PGPPATH
 
-static struct pgp_cache {
+struct pgp_cache
+{
   char *what;
   char *dflt;
   struct pgp_cache *next;
-} * id_defaults = NULL;
+};
 
-typedef struct
-{
-  KEYINFO *k;
-  PGPUID *a;
-} pgp_key_t;
+static struct pgp_cache *id_defaults = NULL;
 
 static char trust_flags[] = "?- +";
 
-static char *pgp_key_abilities(int flags)
+static char *pgp_key_abilities (int flags)
 {
   static char buff[3];
-  
-  if(!(flags & KEYFLAG_CANENCRYPT))
+
+  if (!(flags & KEYFLAG_CANENCRYPT))
     buff[0] = '-';
-  else if(flags & KEYFLAG_PREFER_SIGNING)
+  else if (flags & KEYFLAG_PREFER_SIGNING)
     buff[0] = '.';
   else
     buff[0] = 'e';
-  
-  if(!(flags & KEYFLAG_CANSIGN))
+
+  if (!(flags & KEYFLAG_CANSIGN))
     buff[1] = '-';
-  else if(flags & KEYFLAG_PREFER_ENCRYPTION)
+  else if (flags & KEYFLAG_PREFER_ENCRYPTION)
     buff[1] = '.';
   else
     buff[1] = 's';
-  
+
   buff[2] = '\0';
-  
+
   return buff;
 }
 
-static void pgp_entry (char *s, size_t l, MUTTMENU *menu, int num)
+static char pgp_flags (int flags)
+{
+  if (flags & KEYFLAG_REVOKED)
+    return 'R';
+  else if (flags & KEYFLAG_EXPIRED)
+    return 'X';
+  else if (flags & KEYFLAG_DISABLED)
+    return 'd';
+  else if (flags & KEYFLAG_CRITICAL)
+    return 'c';
+  else 
+    return ' ';
+}
+
+static pgp_key_t *pgp_principal_key (pgp_key_t *key)
 {
-  pgp_key_t *KeyTable = (pgp_key_t *) menu->data;
+  if (key->flags & KEYFLAG_SUBKEY && key->parent)
+    return key->parent;
+  else
+    return key;
+}
 
+static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
+{
+  pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
+  pgp_uid_t *entry;
+  pgp_key_t *key;
+  
+  entry = KeyTable[num];
+  key = pgp_principal_key (entry->parent);
+  
   snprintf (s, l, "%4d %c%c %4d/0x%s %-4s %2s  %s",
-           num + 1,
-           trust_flags[KeyTable[num].a->trust & 0x03],
-            (KeyTable[num].k->flags & KEYFLAG_CRITICAL ?
-            'c' : ' '),
-           KeyTable[num].k->keylen, 
-           _pgp_keyid(KeyTable[num].k),
-           KeyTable[num].k->algorithm, 
-           pgp_key_abilities(KeyTable[num].k->flags),
-           KeyTable[num].a->addr);
+           num + 1, trust_flags[entry->trust & 0x03],
+           pgp_flags (key->flags),
+           entry->parent->keylen,
+           _pgp_keyid (key),
+           key->algorithm,
+           pgp_key_abilities (key->flags),
+           entry->addr);
 }
 
-static int pgp_search (MUTTMENU *m, regex_t *re, int n)
+static int pgp_search (MUTTMENU * m, regex_t * re, int n)
 {
   char buf[LONG_STRING];
-  
+
   pgp_entry (buf, sizeof (buf), m, n);
   return (regexec (re, buf, 0, NULL, 0));
 }
@@ -97,82 +119,55 @@ static int pgp_search (MUTTMENU *m, regex_t *re, int n)
 static int pgp_compare (const void *a, const void *b)
 {
   int r;
-  
-  pgp_key_t *s = (pgp_key_t *) a;
-  pgp_key_t *t = (pgp_key_t *) b;
 
-  if((r = mutt_strcasecmp (s->a->addr, t->a->addr)) != 0)
+  pgp_uid_t **s = (pgp_uid_t **) a;
+  pgp_uid_t **t = (pgp_uid_t **) b;
+
+  if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)) != 0)
     return r;
   else
-    return mutt_strcasecmp(pgp_keyid(s->k), pgp_keyid(t->k));
+    return mutt_strcasecmp (pgp_keyid ((*s)->parent), pgp_keyid ((*t)->parent));
 }
 
-static KEYINFO *pgp_select_key (struct pgp_vinfo *pgp,
-                               LIST *keys, 
-                               ADDRESS *p, const char *s)
+static pgp_key_t *pgp_select_key (struct pgp_vinfo *pgp,
+                                 pgp_key_t *keys,
+                                 ADDRESS * p, const char *s)
 {
   int keymax;
-  pgp_key_t *KeyTable;
+  pgp_uid_t **KeyTable;
   MUTTMENU *menu;
-  LIST *a;
-  int i;  
-  int done = 0;
-  LIST *l;
+  int i, done = 0;
   char helpstr[SHORT_STRING], buf[LONG_STRING];
   char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
   FILE *fp, *devnull;
   pid_t thepid;
-  KEYINFO *info;
-  
-  
-  for (i = 0, l = keys; l; l = l->next)
+  pgp_key_t *kp;
+  pgp_uid_t *a;
+
+  for (i = 0, kp = keys; kp; kp = kp->next)
   {
-    int did_main_key = 0;
-    
-    info = (KEYINFO *) l->data;
-    a = info->address;
-   retry1:
-    for (; a; i++, a = a->next)
+    for (a = kp->address; a; i++, a = a->next)
       ;
-
-    if(!did_main_key && info->flags & KEYFLAG_SUBKEY && info->mainkey)
-    {
-      did_main_key = 1;
-      a = info->mainkey->address;
-      goto retry1;
-    }
   }
-    
-  if (i == 0) return NULL;
+
+  if (i == 0)
+    return NULL;
 
   keymax = i;
-  KeyTable = safe_malloc (sizeof (pgp_key_t) * i);
+  KeyTable = safe_malloc (sizeof (pgp_key_t *) * i);
 
-  for (i = 0, l = keys; l; l = l->next)
+  for (i = 0, kp = keys; kp; kp = kp->next)
   {
-    int did_main_key = 0;
-    info = (KEYINFO *)l->data;
-    a = info->address;
-   retry2:    
-    for (; a ; i++, a = a->next)
-    {
-      KeyTable[i].k = (KEYINFO *) l->data;
-      KeyTable[i].a = (PGPUID *)a->data;
-    }
-    if(!did_main_key && info->flags & KEYFLAG_SUBKEY && info->mainkey)
-    {
-      did_main_key = 1;
-      a = info->mainkey->address;
-      goto retry2;
-    }
+    for (a = kp->address; a; i++, a = a->next)
+      KeyTable[i] = a;
   }
-  
-  qsort (KeyTable, i, sizeof (pgp_key_t), pgp_compare);
+
+  qsort (KeyTable, i, sizeof (pgp_key_t *), pgp_compare);
 
   helpstr[0] = 0;
   mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_PGP, OP_EXIT);
   strcat (helpstr, buf);
-  mutt_make_help (buf, sizeof (buf), _("Select  "), MENU_PGP, 
+  mutt_make_help (buf, sizeof (buf), _("Select  "), MENU_PGP,
                  OP_GENERIC_SELECT_ENTRY);
   strcat (helpstr, buf);
   mutt_make_help (buf, sizeof (buf), _("Check key  "), MENU_PGP, OP_VERIFY_KEY);
@@ -195,114 +190,141 @@ static KEYINFO *pgp_select_key (struct pgp_vinfo *pgp,
     strcat (buf, s);
   menu->title = buf;
 
-  info = NULL;
-  
+  kp = NULL;
+
   while (!done)
   {
     switch (mutt_menuLoop (menu))
     {
 
-      case OP_VERIFY_KEY:
+    case OP_VERIFY_KEY:
 
-        mutt_mktemp (tempfile);
-       if ((devnull = fopen ("/dev/null", "w")) == NULL)
+      mutt_mktemp (tempfile);
+      if ((devnull = fopen ("/dev/null", "w")) == NULL)
+      {
+       mutt_perror _("Can't open /dev/null");
+       break;
+      }
+      if ((fp = safe_fopen (tempfile, "w")) == NULL)
+      {
+       fclose (devnull);
+       mutt_perror _("Can't create temporary file");
+       break;
+      }
+
+      mutt_message _("Invoking PGP...");
+
+      if ((thepid = pgp->invoke_verify_key (pgp, NULL, NULL, NULL, -1,
+                   fileno (fp), fileno (devnull),
+                   pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent)))) == -1)
+      {
+       mutt_perror _("Can't create filter");
+       unlink (tempfile);
+       fclose (fp);
+       fclose (devnull);
+      }
+
+      mutt_wait_filter (thepid);
+      fclose (fp);
+      fclose (devnull);
+      mutt_clear_error ();
+      snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), 
+               pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent)));
+      mutt_do_pager (cmd, tempfile, 0, NULL);
+      menu->redraw = REDRAW_FULL;
+
+      break;
+
+    case OP_VIEW_ID:
+
+      mutt_message (KeyTable[menu->current]->addr);
+      break;
+
+    case OP_GENERIC_SELECT_ENTRY:
+
+
+      /* XXX make error reporting more verbose */
+      
+      if (option (OPTPGPCHECKTRUST))
+      {
+       pgp_key_t *key, *principal;
+       
+       key = KeyTable[menu->current]->parent;
+       principal = pgp_principal_key (key);
+       
+       if ((key->flags | principal->flags) & KEYFLAG_CANTUSE)
        {
-         mutt_perror _("Can't open /dev/null");
+         mutt_error _("This key can't be used: expired/disabled/revoked.");
          break;
        }
-       if ((fp = safe_fopen (tempfile, "w")) == NULL)
+      }
+      
+      if (option (OPTPGPCHECKTRUST) &&
+         (KeyTable[menu->current]->trust & 0x03) < 3)
+      {
+       char *s = "";
+       char buff[LONG_STRING];
+
+       switch (KeyTable[menu->current]->trust & 0x03)
        {
-         fclose (devnull);
-         mutt_perror _("Can't create temporary file");
+       case 0:
+         s = N_("This ID's trust level is undefined.");
+         break;
+       case 1:
+         s = N_("This ID is not trusted.");
+         break;
+       case 2:
+         s = N_("This ID is only marginally trusted.");
          break;
-        }
-
-       mutt_message _("Invoking PGP...");
-       
-        if((thepid = pgp->invoke_verify_key(pgp, NULL, NULL, NULL, -1,
-                                          fileno(fp), fileno(devnull), 
-                                          pgp_keyid(KeyTable[menu->current].k))) == -1)
-        {
-         mutt_perror _("Can't create filter");
-         unlink (tempfile);
-         fclose (fp);
-         fclose (devnull);
        }
 
-       mutt_wait_filter (thepid);
-       fclose (fp);
-       fclose (devnull);
-       mutt_clear_error ();
-        snprintf(cmd, sizeof(cmd), _("Key ID: 0x%s"), pgp_keyid(KeyTable[menu->current].k));
-       mutt_do_pager (cmd, tempfile, 0, NULL);
-       menu->redraw = REDRAW_FULL;
-       
-       break;
+       snprintf (buff, sizeof (buff), _("%s Do you really want to use it?"),
+                 _(s));
 
-      case OP_VIEW_ID:
-        
-        mutt_message (KeyTable[menu->current].a->addr);
-        break;
-      
-      case OP_GENERIC_SELECT_ENTRY:
-
-       if (option (OPTPGPCHECKTRUST) && 
-           (KeyTable[menu->current].a->trust & 0x03) < 3) 
+       if (mutt_yesorno (buff, 0) != 1)
        {
-         char *s = "";
-         char buff[LONG_STRING];
-
-         switch (KeyTable[menu->current].a->trust & 0x03)
-         {
-         case 0: s = N_("This ID's trust level is undefined."); break;
-         case 1: s = N_("This ID is not trusted."); break;
-         case 2: s = N_("This ID is only marginally trusted."); break;
-         }
-
-         snprintf (buff, sizeof(buff), _("%s Do you really want to use it?"),
-                   _(s));
-
-         if (mutt_yesorno (buff, 0) != 1)
-         {
-           mutt_clear_error ();
-           break;
-         }
+         mutt_clear_error ();
+         break;
        }
+      }
 
-        info = KeyTable[menu->current].k;
-       done = 1;
-       break;
+# if 0
+      kp = pgp_principal_key (KeyTable[menu->current]->parent);
+# else
+      kp = KeyTable[menu->current]->parent;
+# endif
+      done = 1;
+      break;
 
-      case OP_EXIT:
+    case OP_EXIT:
 
-        info = NULL;
-       done = 1;
-       break;
+      kp = NULL;
+      done = 1;
+      break;
     }
   }
 
   mutt_menuDestroy (&menu);
   safe_free ((void **) &KeyTable);
 
-  return (info);
+  return (kp);
 }
 
-char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *whatfor,
-                      short abilities, char **alg)
+pgp_key_t *pgp_ask_for_key (struct pgp_vinfo *pgp, char *tag, char *whatfor,
+                           short abilities, pgp_ring_t keyring)
 {
-  KEYINFO *key;
-  char *key_id;
+  pgp_key_t *key;
   char resp[SHORT_STRING];
   struct pgp_cache *l = NULL;
 
   resp[0] = 0;
-  if (whatfor) 
+  if (whatfor)
   {
 
     for (l = id_defaults; l; l = l->next)
       if (!mutt_strcasecmp (whatfor, l->what))
       {
-       strcpy (resp, NONULL(l->dflt));
+       strcpy (resp, NONULL (l->dflt));
        break;
       }
   }
@@ -313,14 +335,14 @@ char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *what
     resp[0] = 0;
     if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
       return NULL;
-    
-    if (whatfor) 
+
+    if (whatfor)
     {
       if (l)
       {
-       safe_free ((void **)&l->dflt);
+       safe_free ((void **) &l->dflt);
        l->dflt = safe_strdup (resp);
-      } 
+      }
       else
       {
        l = safe_malloc (sizeof (struct pgp_cache));
@@ -331,15 +353,9 @@ char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *what
       }
     }
 
-    if ((key = ki_getkeybystr (pgp, resp, db, abilities)))
-    {
-      key_id = safe_strdup(pgp_keyid (key));
+    if ((key = pgp_getkeybystr (pgp, resp, abilities, keyring)))
+      return key;
 
-      if (alg) 
-       *alg = safe_strdup(pgp_pkalg_to_mic(key->algorithm));
-      
-      return (key_id);
-    }
     BEEP ();
   }
   /* not reached */
@@ -347,7 +363,7 @@ char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *what
 
 /* generate a public key attachment */
 
-BODY *pgp_make_key_attachment (char * tempf)
+BODY *pgp_make_key_attachment (char *tempf)
 {
   BODY *att;
   char buff[LONG_STRING];
@@ -357,54 +373,60 @@ BODY *pgp_make_key_attachment (char * tempf)
   FILE *devnull;
   struct stat sb;
   pid_t thepid;
-  KEYINFO *db;
-  struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_EXPORT);
+  pgp_key_t *key;
+  struct pgp_vinfo *pgp = pgp_get_vinfo (PGP_EXPORT);
 
-  if(!pgp)
+  if (!pgp)
     return NULL;
-  
+
   unset_option (OPTPGPCHECKTRUST);
-  
-  db = pgp->read_pubring(pgp);
-  id = pgp_ask_for_key (pgp, db, _("Please enter the key ID: "), NULL, 0, NULL);
-  pgp_close_keydb(&db);
-  
-  if(!id)
-    return NULL;
 
-  if (!tempf) {
+  key = pgp_ask_for_key (pgp, _("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
+
+  if (!key)    return NULL;
+
+  id = safe_strdup (pgp_keyid (pgp_principal_key(key)));
+  pgp_free_key (&key);
+  
+  if (!tempf)
+  {
     mutt_mktemp (tempfb);
     tempf = tempfb;
   }
 
-  if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) {
+  if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL)
+  {
     mutt_perror _("Can't create temporary file");
-    safe_free ((void **)&id);
+    safe_free ((void **) &id);
     return NULL;
   }
 
-  if ((devnull = fopen ("/dev/null", "w")) == NULL) {
+  if ((devnull = fopen ("/dev/null", "w")) == NULL)
+  {
     mutt_perror _("Can't open /dev/null");
-    safe_free ((void **)&id);
+    safe_free ((void **) &id);
     fclose (tempfp);
-    if (tempf == tempfb) unlink (tempf);
+    if (tempf == tempfb)
+      unlink (tempf);
     return NULL;
   }
 
-  if ((thepid = pgp->invoke_export(pgp,
-                                  NULL, NULL, NULL, -1, 
-                                  fileno(tempfp), fileno(devnull), id)) == -1)
+  mutt_message _("Invoking pgp...");
+  
+  if ((thepid = 
+       pgp->invoke_export (pgp, NULL, NULL, NULL, -1,
+                          fileno (tempfp), fileno (devnull), id)) == -1)
   {
     mutt_perror _("Can't create filter");
     unlink (tempf);
     fclose (tempfp);
     fclose (devnull);
-    safe_free ((void **)&id);
+    safe_free ((void **) &id);
     return NULL;
   }
+
   mutt_wait_filter (thepid);
-  
+
   fclose (tempfp);
   fclose (devnull);
 
@@ -412,86 +434,89 @@ BODY *pgp_make_key_attachment (char * tempf)
   att->filename = safe_strdup (tempf);
   att->unlink = 1;
   att->type = TYPEAPPLICATION;
-  att->subtype = safe_strdup ("pgp-keys"); 
+  att->subtype = safe_strdup ("pgp-keys");
   snprintf (buff, sizeof (buff), _("PGP Key 0x%s."), id);
   att->description = safe_strdup (buff);
   mutt_update_encoding (att);
-  
+
   stat (tempf, &sb);
   att->length = sb.st_size;
 
-  safe_free ((void **)&id);  
+  safe_free ((void **) &id);
   return att;
 }
 
-static char *mutt_stristr (char *haystack, char *needle)
+static LIST *pgp_add_string_to_hints (LIST *hints, const char *str)
 {
-  char *p, *q;
-
-  if (!haystack)
-    return NULL;
-  if (!needle)
-    return (haystack);
-
-  while (*(p = haystack))
+  char *scratch = safe_strdup (str);
+  char *t;
+  
+  t = strtok (scratch, " \n");
+  while (t)
   {
-    for (q = needle ; *p && *q && tolower (*p) == tolower (*q) ; p++, q++)
-      ;
-    if (!*q)
-      return (haystack);
-    haystack++;
+    hints = mutt_add_list (hints, t);
+    t = strtok (NULL, " \n");
   }
-  return NULL;
+
+  safe_free ((void **) &scratch);
+  return hints;
 }
 
-KEYINFO *ki_getkeybyaddr (struct pgp_vinfo *pgp, 
-                         ADDRESS *a, KEYINFO *k, short abilities)
+
+pgp_key_t *pgp_getkeybyaddr (struct pgp_vinfo * pgp,
+                         ADDRESS * a, short abilities, pgp_ring_t keyring)
 {
   ADDRESS *r, *p;
-  LIST *l = NULL, *t = NULL;
-  LIST *q;
+  LIST *hints = NULL;
   int weak = 0;
   int weak_association;
   int match;
-  int did_main_key;
-  PGPUID *u;
+  pgp_uid_t *q;
+  pgp_key_t *keys, *k, *kn;
+  pgp_key_t *matches = NULL;
+  pgp_key_t **last = &matches;
   
-  dprint (5, (debugfile, "ki_getkeybyaddr: looking for %s <%s>.",
-             a->personal, a->mailbox));
+  if (a && a->mailbox)
+    hints = pgp_add_string_to_hints (hints, a->mailbox);
+  if (a && a->personal)
+    hints = pgp_add_string_to_hints (hints, a->personal);
+
+  mutt_message _("Looking for keys...");
+  keys = pgp->get_candidates (pgp, keyring, hints);
 
+  mutt_free_list (&hints);
   
-  for ( ; k ; k = k->next)
+  if (!keys)
+    return NULL;
+  
+  dprint (5, (debugfile, "pgp_getkeybyaddr: looking for %s <%s>.",
+             a->personal, a->mailbox));
+
+
+  for (k = keys; k; k = kn)
   {
+    kn = k->next;
+
     dprint (5, (debugfile, "  looking at key: %s\n",
                pgp_keyid (k)));
-    
-    if(k->flags & (KEYFLAG_REVOKED | KEYFLAG_EXPIRED | KEYFLAG_DISABLED))
-    {
-      dprint (5, (debugfile, "  key disabled/revoked/expired\n"));
-      continue;
-    }
-    
-    if(abilities && !(k->flags & abilities))
+
+    if (abilities && !(k->flags & abilities))
     {
       dprint (5, (debugfile, "  insufficient abilities: Has %x, want %x\n",
                  k->flags, abilities));
       continue;
     }
-    
+
     q = k->address;
-    did_main_key = 0;
     weak_association = 1;
     match = 0;
-    
-    retry:
-    
-    for (;q ; q = q->next)
+
+    for (; q; q = q->next)
     {
-      u = (PGPUID *) q->data;
-      r = rfc822_parse_adrlist(NULL, u->addr);
+      r = rfc822_parse_adrlist (NULL, q->addr);
 
-      
-      for(p = r; p && weak_association; p = p->next) 
+
+      for (p = r; p && weak_association; p = p->next)
       {
        if ((p->mailbox && a->mailbox &&
             mutt_strcasecmp (p->mailbox, a->mailbox) == 0) ||
@@ -500,116 +525,138 @@ KEYINFO *ki_getkeybyaddr (struct pgp_vinfo *pgp,
        {
          match = 1;
 
-         if(((u->trust & 0x03) == 3) &&
-            (p->mailbox && a->mailbox && !mutt_strcasecmp(p->mailbox, a->mailbox)))
+         if (((q->trust & 0x03) == 3) &&
+             (p->mailbox && a->mailbox && !mutt_strcasecmp (p->mailbox, a->mailbox)))
            weak_association = 0;
        }
       }
-      rfc822_free_address(&r);
+      rfc822_free_address (&r);
     }
 
-    if(match)
+    if (match)
     {
-      t = mutt_new_list ();
-      t->data = (void *) k;
-      t->next = l;
-      l = t;
-      
-      if(weak_association)
-       weak = 1;
+      pgp_key_t *_p, *_k;
+
+      _k = pgp_principal_key (k);
       
-    }
+      *last = _k;
+      kn = pgp_remove_key (&keys, _k);
 
-    if(!did_main_key && !match && k->flags & KEYFLAG_SUBKEY && k->mainkey)
-    {
-      did_main_key = 1;
-      q = k->mainkey->address;
-      goto retry;
+      /* start with k, not with _k: k is always a successor of _k. */
+      
+      for (_p = k; _p; _p = _p->next)
+      {
+       if (!_p->next)
+       {
+         last = &_p->next;
+         break;
+       }
+      }
     }
   }
+
+  pgp_free_key (&keys);
   
-  if (l)
+  if (matches)
   {
-    if (l->next || weak)
+    if (matches->next || weak)
     {
       /* query for which key the user wants */
-      k = pgp_select_key (pgp, l, a, NULL);
+      k = pgp_select_key (pgp, matches, a, NULL);
+      if (k) 
+       pgp_remove_key (&matches, k);
+
+      pgp_free_key (&matches);
     }
     else
-      k = (KEYINFO *)l->data;
-
-    /* mutt_free_list() frees the .data member, so clear the pointers */
-
-    for(t = l; t; t = t->next)
-      t->data = NULL;
+      k = matches;
     
-    mutt_free_list (&l);
+    return k;
   }
 
-  return (k);
+  return NULL;
 }
 
-KEYINFO *ki_getkeybystr (struct pgp_vinfo *pgp,
-                        char *p, KEYINFO *k, short abilities)
+pgp_key_t *pgp_getkeybystr (struct pgp_vinfo * pgp,
+                        char *p, short abilities, pgp_ring_t keyring)
 {
-  LIST *t = NULL, *l = NULL;
-  LIST *a;
+  LIST *hints = NULL;
+  pgp_key_t *keys;
+  pgp_key_t *matches = NULL;
+  pgp_key_t **last = &matches;
+  pgp_key_t *k, *kn;
+  pgp_uid_t *a;
+  short match;
+
+  mutt_message _("Looking for keys...");
+  
+  hints = pgp_add_string_to_hints (hints, p);
+  keys = pgp->get_candidates (pgp, keyring, hints);
+  mutt_free_list (&hints);
+
+  if (!keys)
+    return NULL;
   
-  for(; k; k = k->next)
+  
+  for (k = keys; k; k = kn)
   {
-    int did_main_key = 0;
-    
-    if(k->flags & (KEYFLAG_REVOKED | KEYFLAG_EXPIRED | KEYFLAG_DISABLED)) 
-      continue;
-    
-    if(abilities && !(k->flags & abilities))
+    kn = k->next;
+    if (abilities && !(k->flags & abilities))
       continue;
 
-    a = k->address;
-    
-    retry:
+    match = 0;
     
-    for(; a ; a = a->next) 
+    for (a = k->address; a; a = a->next)
     {
-      dprint (5, (debugfile, "ki_getkeybystr: matching \"%s\" against key %s, \"%s\": ",
-                 p, pgp_keyid (k), ((PGPUID *)a->data)->addr));
-      if (!*p || mutt_strcasecmp (p, pgp_keyid(k)) == 0 ||
-         (!mutt_strncasecmp(p, "0x", 2) && !mutt_strcasecmp(p+2, pgp_keyid(k))) ||
-         (option(OPTPGPLONGIDS) && !mutt_strncasecmp(p, "0x", 2) &&
-          !mutt_strcasecmp(p+2, k->keyid+8)) ||
-         mutt_stristr(((PGPUID *)a->data)->addr,p))
+      dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\": ",
+                 p, pgp_keyid (k), a->addr));
+      if (!*p || mutt_strcasecmp (p, pgp_keyid (k)) == 0 ||
+         (!mutt_strncasecmp (p, "0x", 2) && !mutt_strcasecmp (p + 2, pgp_keyid (k))) ||
+         (option (OPTPGPLONGIDS) && !mutt_strncasecmp (p, "0x", 2) &&
+          !mutt_strcasecmp (p + 2, k->keyid + 8)) ||
+         mutt_stristr (a->addr, p))
       {
        dprint (5, (debugfile, "match.\n"));
-       t = mutt_new_list ();
-       t->data = (void *)k;
-       t->next = l;
-       l = t;
+       match = 1;
        break;
       }
-      else
-       dprint (5, (debugfile, "no match.\n"));
     }
     
-    if(!did_main_key && k->flags & KEYFLAG_SUBKEY && k->mainkey)
+    if (match)
     {
-      did_main_key = 1;
-      a = k->mainkey->address;
-      goto retry;
+      pgp_key_t *_p, *_k;
+
+      _k = pgp_principal_key (k);
+      
+      *last = _k;
+      kn = pgp_remove_key (&keys, _k);
+
+      /* start with k, not with _k: k is always a successor of _k. */
+      
+      for (_p = k; _p; _p = _p->next)
+      {
+       if (!_p->next)
+       {
+         last = &_p->next;
+         break;
+       }
+      }
     }
   }
 
-  if (l)
-  {
-    k = pgp_select_key (pgp, l, NULL, p);
-    set_option(OPTNEEDREDRAW);
-
-    for(t = l; t; t = t->next)
-      t->data = NULL;
+  pgp_free_key (&keys);
 
-    mutt_free_list (&l);
+  if (matches)
+  {
+    k = pgp_select_key (pgp, matches, NULL, p);
+    if (k) 
+      pgp_remove_key (&matches, k);
+    
+    pgp_free_key (&matches);
+    return k;
   }
 
-  return (k);
+  return NULL;
 }
 
 
index c093c21651cfa5f3899eb6edfa2db07cc451e5de..ff878e1b681c767c0e6f5bd506d187d0eec6c1d5 100644 (file)
@@ -17,7 +17,7 @@
  *     License along with this program; if not, write to the Free
  *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
  *     02139, USA.
- */ 
+ */
 
 
 #include <stdio.h>
 static unsigned char *pbuf = NULL;
 static size_t plen = 0;
 
-enum packet_tags {
-  PT_RES0 = 0,         /* reserved */
-  PT_ESK,              /* Encrypted Session Key */
-  PT_SIG,              /* Signature Packet */
-  PT_CESK,             /* Conventionally Encrypted Session Key Packet */
-  PT_OPS,              /* One-Pass Signature Packet */
-  PT_SECKEY,           /* Secret Key Packet */
-  PT_PUBKEY,           /* Public Key Packet */
-  PT_SUBSECKEY,                /* Secret Subkey Packet */
-  PT_COMPRESSED,       /* Compressed Data Packet */
-  PT_SKE,              /* Symmetrically Encrypted Data Packet */
-  PT_MARKER,           /* Marker Packet */
-  PT_LITERAL,          /* Literal Data Packet */
-  PT_TRUST,            /* Trust Packet */
-  PT_NAME,             /* Name Packet */
-  PT_SUBKEY,           /* Subkey Packet */
-  PT_RES15,            /* Reserved */
-  PT_COMMENT           /* Comment Packet */
+enum packet_tags
+{
+  PT_RES0 = 0,                 /* reserved */
+  PT_ESK,                      /* Encrypted Session Key */
+  PT_SIG,                      /* Signature Packet */
+  PT_CESK,                     /* Conventionally Encrypted Session Key Packet */
+  PT_OPS,                      /* One-Pass Signature Packet */
+  PT_SECKEY,                   /* Secret Key Packet */
+  PT_PUBKEY,                   /* Public Key Packet */
+  PT_SUBSECKEY,                        /* Secret Subkey Packet */
+  PT_COMPRESSED,               /* Compressed Data Packet */
+  PT_SKE,                      /* Symmetrically Encrypted Data Packet */
+  PT_MARKER,                   /* Marker Packet */
+  PT_LITERAL,                  /* Literal Data Packet */
+  PT_TRUST,                    /* Trust Packet */
+  PT_NAME,                     /* Name Packet */
+  PT_SUBKEY,                   /* Subkey Packet */
+  PT_RES15,                    /* Reserved */
+  PT_COMMENT                   /* Comment Packet */
 };
 
 /* FIXME I can't find where those strings are displayed! */
-const char *pgp_packet_name[] = {
+const char *pgp_packet_name[] =
+{
   N_("reserved"),
   N_("Encrypted Session Key"),
   N_("Signature Packet"),
@@ -77,17 +79,24 @@ const char *pgp_packet_name[] = {
   N_("Comment Packet")
 };
 
-const char *pgp_pkalgbytype(unsigned char type)
+const char *pgp_pkalgbytype (unsigned char type)
 {
-  switch(type)
+  switch (type)
   {
-    case 1: return "RSA";
-    case 2: return "RSA";
-    case 3: return "RSA";
-    case 16: return "ElG";
-    case 17: return "DSA";
-    case 20: return "ElG";
-    default: return "unk";
+  case 1:
+    return "RSA";
+  case 2:
+    return "RSA";
+  case 3:
+    return "RSA";
+  case 16:
+    return "ElG";
+  case 17:
+    return "DSA";
+  case 20:
+    return "ElG";
+  default:
+    return "unk";
   }
 }
 
@@ -97,25 +106,36 @@ static struct
   char *pkalg;
   char *micalg;
 }
-pktomic[] = 
+pktomic[] =
 {
-  { "RSA", "pgp-md5" },
-  { "ElG", "pgp-rmd160" },
-  { "DSA", "pgp-sha1" },
-  { NULL, "x-unknown" }
+  {
+    "RSA", "pgp-md5"
+  }
+  ,
+  {
+    "ElG", "pgp-rmd160"
+  }
+  ,
+  {
+    "DSA", "pgp-sha1"
+  }
+  ,
+  {
+    NULL, "x-unknown"
+  }
 };
 
 
-const char *pgp_pkalg_to_mic(const char *alg)
+const char *pgp_pkalg_to_mic (const char *alg)
 {
   int i;
-  
-  for(i = 0; pktomic[i].pkalg; i++)
+
+  for (i = 0; pktomic[i].pkalg; i++)
   {
-    if(!mutt_strcasecmp(pktomic[i].pkalg, alg))
+    if (!mutt_strcasecmp (pktomic[i].pkalg, alg))
       break;
   }
-  
+
   return pktomic[i].micalg;
 }
 
@@ -124,255 +144,349 @@ const char *pgp_pkalg_to_mic(const char *alg)
 
 #if 0
 
-static const char *hashalgbytype(unsigned char type)
+static const char *hashalgbytype (unsigned char type)
 {
-  switch(type)
+  switch (type)
   {
-    case 1: return "MD5";
-    case 2: return "SHA1";
-    case 3: return "RIPE-MD/160";
-    case 4: return "HAVAL";
-    default: return "unknown";
+  case 1:
+    return "MD5";
+  case 2:
+    return "SHA1";
+  case 3:
+    return "RIPE-MD/160";
+  case 4:
+    return "HAVAL";
+  default:
+    return "unknown";
   }
 }
 
 #endif
 
-short pgp_canencrypt(unsigned char type)
+short pgp_canencrypt (unsigned char type)
 {
-  switch(type)
+  switch (type)
   {
-    case 1:
-    case 2:
-    case 16:
-    case 20:
-       return 1;
-    default:
-        return 0;
+  case 1:
+  case 2:
+  case 16:
+  case 20:
+    return 1;
+  default:
+    return 0;
   }
 }
 
-short pgp_cansign(unsigned char type)
+short pgp_cansign (unsigned char type)
 {
-  switch(type)
+  switch (type)
   {
-    case 1:
-    case 3:
-    case 16:
-    case 17:
-    case 20:
-       return 1;
-    default:
-       return 0;
+  case 1:
+  case 3:
+  case 16:
+  case 17:
+  case 20:
+    return 1;
+  default:
+    return 0;
   }
 }
 
 /* return values: 
- *
+
  * 1 = sign only
  * 2 = encrypt only
  * 3 = both
  */
 
-short pgp_get_abilities(unsigned char type)
+short pgp_get_abilities (unsigned char type)
 {
-  return (pgp_canencrypt(type) << 1) | pgp_cansign(type);
+  return (pgp_canencrypt (type) << 1) | pgp_cansign (type);
 }
 
-static int read_material(size_t material, size_t *used, FILE *fp)
+static int read_material (size_t material, size_t * used, FILE * fp)
 {
-  if(*used + material >= plen)
+  if (*used + material >= plen)
   {
     unsigned char *p;
     size_t nplen;
-    
+
     nplen = *used + material + CHUNKSIZE;
 
-    if(!(p = realloc(pbuf, nplen)))
+    if (!(p = realloc (pbuf, nplen)))
     {
-      mutt_perror("realloc");
+      mutt_perror ("realloc");
       return -1;
     }
     plen = nplen;
     pbuf = p;
   }
-      
-  if(fread(pbuf + *used, 1, material, fp) < material)
+
+  if (fread (pbuf + *used, 1, material, fp) < material)
   {
-    mutt_perror("fread");
+    mutt_perror ("fread");
     return -1;
   }
-  
+
   *used += material;
   return 0;
 }
 
-static unsigned char *pgp_read_packet(FILE *fp, size_t *len)
+static unsigned char *pgp_read_packet (FILE * fp, size_t * len)
 {
   size_t used = 0;
   long startpos;
   unsigned char ctb;
   unsigned char b;
   size_t material;
-  
-  startpos = ftell(fp);
-  
-  if(!plen)
+
+  startpos = ftell (fp);
+
+  if (!plen)
   {
     plen = CHUNKSIZE;
-    pbuf = safe_malloc(plen);
+    pbuf = safe_malloc (plen);
   }
 
-  if(fread(&ctb, 1, 1, fp) < 1)
+  if (fread (&ctb, 1, 1, fp) < 1)
   {
-    if(!feof(fp))
-       mutt_perror("fread"); 
+    if (!feof (fp))
+      mutt_perror ("fread");
     goto bail;
   }
 
-  if(!(ctb & 0x80))
+  if (!(ctb & 0x80))
   {
     goto bail;
   }
 
-  if(ctb & 0x40)       /* handle PGP 5.0 packets. */
+  if (ctb & 0x40)              /* handle PGP 5.0 packets. */
   {
     int partial = 0;
-    pbuf[0] = ctb; used++;
-    
-    do {
-      if(fread(&b, 1, 1, fp) < 1)
+    pbuf[0] = ctb;
+    used++;
+
+    do
+    {
+      if (fread (&b, 1, 1, fp) < 1)
       {
-       mutt_perror("fread");
+       mutt_perror ("fread");
        goto bail;
       }
-      
-      if(b < 192)
+
+      if (b < 192)
       {
        material = b;
        partial = 0;
        material -= 1;
-      } 
-      else if(192 <= b && b <= 223)
+      }
+      else if (192 <= b && b <= 223)
       {
        material = (b - 192) * 256;
-       if(fread(&b, 1, 1, fp) < 1)
+       if (fread (&b, 1, 1, fp) < 1)
        {
-         mutt_perror("fread");
+         mutt_perror ("fread");
          goto bail;
        }
        material += b + 192;
        partial = 0;
        material -= 2;
       }
-      else if(b < 255)
+      else if (b < 255)
       {
        material = 1 << (b & 0x1f);
        partial = 1;
        material -= 1;
       }
-      else /* b == 255 */
+      else
+       /* b == 255 */
       {
        unsigned char buf[4];
-       if( fread( buf, 4, 1, fp ) < 1)
+       if (fread (buf, 4, 1, fp) < 1)
        {
-          mutt_perror("fread");
-          goto bail;
+         mutt_perror ("fread");
+         goto bail;
        }
-       /*assert( sizeof(material) >= 4 );*/
-       material  = buf[0] << 24;
+       /*assert( sizeof(material) >= 4 ); */
+       material = buf[0] << 24;
        material |= buf[1] << 16;
        material |= buf[2] << 8;
        material |= buf[3];
        partial = 0;
        material -= 5;
       }
-    
-      if(read_material(material, &used, fp) == -1)
+
+      if (read_material (material, &used, fp) == -1)
        goto bail;
 
-    } while (partial);
+    }
+    while (partial);
   }
-  else         /* Old-Style PGP */
+  else
+    /* Old-Style PGP */
   {
     int bytes = 0;
     pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
     used++;
-    
-    switch(ctb & 0x03)
+
+    switch (ctb & 0x03)
     {
       case 0:
       {
-        if(fread(&b, 1, 1, fp) < 1)
+       if (fread (&b, 1, 1, fp) < 1)
        {
-         mutt_perror("fread");
+         mutt_perror ("fread");
          goto bail;
        }
-       
+
        material = b;
        break;
       }
-    
+
       case 1:
-       bytes = 2;
-      
+      bytes = 2;
+
       case 2:
       {
        int i;
 
-       if(!bytes) bytes = 4;
-       
+       if (!bytes)
+         bytes = 4;
+
        material = 0;
-       
-       for(i = 0; i < bytes; i++)
+
+       for (i = 0; i < bytes; i++)
        {
-         if(fread(&b, 1, 1, fp) < 1)
+         if (fread (&b, 1, 1, fp) < 1)
          {
-           mutt_perror("fread");
+           mutt_perror ("fread");
            goto bail;
          }
-         
+
          material = (material << 8) + b;
        }
        break;
       }
-      
+
       default:
-        goto bail;
+      goto bail;
     }
-    
-    if(read_material(material, &used, fp) == -1)
+
+    if (read_material (material, &used, fp) == -1)
       goto bail;
   }
-  
-  if(len)
+
+  if (len)
     *len = used;
-  
+
   return pbuf;
-  
-  bail:
-  
-  fseek(fp, startpos, SEEK_SET);
+
+bail:
+
+  fseek (fp, startpos, SEEK_SET);
   return NULL;
 }
 
-static KEYINFO *pgp_new_keyinfo(void)
+static pgp_key_t *pgp_new_keyinfo (void)
 {
-  KEYINFO *p;
+  return safe_calloc (sizeof (pgp_key_t), 1);
+}
 
-  p = safe_malloc(sizeof(KEYINFO));
-  p->keyid = NULL;
-  p->address = NULL;
-  p->flags = 0;
-  p->next = NULL;
-  p->keylen = 0;
+void pgp_free_uid (pgp_uid_t ** upp)
+{
+  pgp_uid_t *up, *q;
 
-  return p;
+  if (!upp || !*upp)
+    return;
+  for (up = *upp; up; up = q)
+  {
+    q = up->next;
+    safe_free ((void **) &up->addr);
+    safe_free ((void **) &up);
+  }
+
+  *upp = NULL;
+}
+
+static void _pgp_free_key (pgp_key_t ** kpp)
+{
+  pgp_key_t *kp;
+
+  if (!kpp || !*kpp)
+    return;
+
+  kp = *kpp;
+
+  pgp_free_uid (&kp->address);
+  safe_free ((void **) &kp->keyid);
+  safe_free ((void **) kpp);
 }
 
-static KEYINFO *pgp_parse_pgp2_key(unsigned char *buff, size_t l)
+pgp_key_t *pgp_remove_key (pgp_key_t ** klist, pgp_key_t * key)
 {
-  KEYINFO *p;
+  pgp_key_t **last;
+  pgp_key_t *p, *q, *r;
+
+  if (!klist || !*klist || !key)
+    return NULL;
+
+  if (key->parent && key->parent != key)
+    key = key->parent;
+
+  last = klist;
+  for (p = *klist; p && p != key; p = p->next)
+    last = &p->next;
+
+  if (!p)
+    return NULL;
+
+  for (q = p->next, r = p; q && q->parent == p; q = q->next)
+    r = q;
+
+  if (r)
+    r->next = NULL;
+
+  *last = q;
+  return q;
+}
+
+void pgp_free_key (pgp_key_t ** kpp)
+{
+  pgp_key_t *p, *q, *r;
+
+  if (!kpp || !*kpp)
+    return;
+
+  if ((*kpp)->parent && (*kpp)->parent != *kpp)
+    *kpp = (*kpp)->parent;
+  
+  /* Order is important here:
+   *
+   * - First free all children.
+   * - If we are an orphan (i.e., our parent was not in the key list),
+   *   free our parent.
+   * - free ourselves.
+   */
+
+  for (p = *kpp; p; p = q)
+  {
+    for (q = p->next; q && q->parent == p; q = r)
+    {
+      r = q->next;
+      _pgp_free_key (&q);
+    }
+    if (p->parent)
+      _pgp_free_key (&p->parent);
+
+    _pgp_free_key (&p);
+  }
+
+  *kpp = NULL;
+}
+
+static pgp_key_t *pgp_parse_pgp2_key (unsigned char *buff, size_t l)
+{
+  pgp_key_t *p;
   unsigned char alg;
   size_t expl;
   unsigned long id;
@@ -381,100 +495,102 @@ static KEYINFO *pgp_parse_pgp2_key(unsigned char *buff, size_t l)
   size_t j;
   int i, k;
   unsigned char scratch[LONG_STRING];
-  
-  if(l < 12)
+
+  if (l < 12)
     return NULL;
-  
-  p = pgp_new_keyinfo();
-  
-  for(i = 0, j = 2; i < 4; i++)
+
+  p = pgp_new_keyinfo ();
+
+  for (i = 0, j = 2; i < 4; i++)
     gen_time = (gen_time << 8) + buff[j++];
-  
-  for(i = 0; i < 2; i++)
+
+  for (i = 0; i < 2; i++)
     exp_days = (exp_days << 8) + buff[j++];
-  
-  if(exp_days && time(NULL) > gen_time + exp_days * 24 * 3600)
+
+  if (exp_days && time (NULL) > gen_time + exp_days * 24 * 3600)
     p->flags |= KEYFLAG_EXPIRED;
-  
+
   alg = buff[j++];
-         
-  p->algorithm = pgp_pkalgbytype(alg);
-  p->flags |= pgp_get_abilities(alg);
-  
+
+  p->algorithm = pgp_pkalgbytype (alg);
+  p->flags |= pgp_get_abilities (alg);
+
   expl = 0;
-  for(i = 0; i < 2; i++)
+  for (i = 0; i < 2; i++)
     expl = (expl << 8) + buff[j++];
-  
+
   p->keylen = expl;
-  
-  expl = (expl + 7)/ 8;
-  if(expl < 4)
+
+  expl = (expl + 7) / 8;
+  if (expl < 4)
     goto bailout;
 
-  
+
   j += expl - 8;
-  
-  for(k = 0; k < 2; k++)
+
+  for (k = 0; k < 2; k++)
   {
-    for(id = 0, i = 0; i < 4; i++)
+    for (id = 0, i = 0; i < 4; i++)
       id = (id << 8) + buff[j++];
-    
-    snprintf((char *)scratch + k * 8, sizeof(scratch) - k * 8, 
-            "%08lX", id);
+
+    snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8,
+             "%08lX", id);
   }
-  
-  p->keyid = safe_strdup((char *)scratch);
-  
+
+  p->keyid = safe_strdup ((char *) scratch);
+
   return p;
-  
-  bailout:
-  
-  safe_free((void **)&p);
+
+bailout:
+
+  safe_free ((void **) &p);
   return NULL;
 }
 
-static void pgp_make_pgp3_fingerprint(unsigned char *buff, size_t l,
-                                     unsigned char *digest)
+static void pgp_make_pgp3_fingerprint (unsigned char *buff, size_t l,
+                                      unsigned char *digest)
 {
   unsigned char dummy;
   SHA_CTX context;
 
-  SHA1_Init(&context);
-  
+  SHA1_Init (&context);
+
   dummy = buff[0] & 0x3f;
 
-  if(dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY)
+  if (dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY)
     dummy = PT_PUBKEY;
 
   dummy = (dummy << 2) | 0x81;
-  SHA1_Update(&context, &dummy, 1);
+  SHA1_Update (&context, &dummy, 1);
   dummy = ((l - 1) >> 8) & 0xff;
-  SHA1_Update(&context, &dummy, 1);
-  dummy = (l - 1) & 0xff; 
-  SHA1_Update(&context, &dummy, 1);
-  SHA1_Update(&context, buff + 1, l - 1);
-  SHA1_Final(digest, &context);
+  SHA1_Update (&context, &dummy, 1);
+  dummy = (l - 1) & 0xff;
+  SHA1_Update (&context, &dummy, 1);
+  SHA1_Update (&context, buff + 1, l - 1);
+  SHA1_Final (digest, &context);
 
 }
 
-static void skip_bignum(unsigned char *buff, size_t l, size_t j,
-                       size_t *toff, size_t n)
+static void skip_bignum (unsigned char *buff, size_t l, size_t j,
+                        size_t * toff, size_t n)
 {
   size_t len;
-  
+
   do
   {
-    len = (buff[j] << 8) + buff[j+1];
+    len = (buff[j] << 8) + buff[j + 1];
     j += (len + 7) / 8 + 2;
-  } while(j <= l && --n > 0);
-  
-  if(toff) *toff = j;
+  }
+  while (j <= l && --n > 0);
+
+  if (toff)
+    *toff = j;
 }
-      
 
-static KEYINFO *pgp_parse_pgp3_key(unsigned char *buff, size_t l)
+
+static pgp_key_t *pgp_parse_pgp3_key (unsigned char *buff, size_t l)
 {
-  KEYINFO *p;
+  pgp_key_t *p;
   unsigned char alg;
   unsigned char digest[SHA_DIGEST_LENGTH];
   unsigned char scratch[LONG_STRING];
@@ -483,98 +599,98 @@ static KEYINFO *pgp_parse_pgp3_key(unsigned char *buff, size_t l)
   int i, k;
   short len;
   size_t j;
-  
-  p = pgp_new_keyinfo();
+
+  p = pgp_new_keyinfo ();
   j = 2;
-  
-  for(i = 0; i < 4; i++)
+
+  for (i = 0; i < 4; i++)
     gen_time = (gen_time << 8) + buff[j++];
 
   p->gen_time = gen_time;
-  
+
   alg = buff[j++];
-  
-  p->algorithm = pgp_pkalgbytype(alg);
-  p->flags |= pgp_get_abilities(alg);
+
+  p->algorithm = pgp_pkalgbytype (alg);
+  p->flags |= pgp_get_abilities (alg);
 
   if (alg == 17)
-    skip_bignum(buff, l, j, &j, 3);
-  else if(alg == 16 || alg == 20 )
-    skip_bignum(buff, l, j, &j, 2);
-  
-  len = (buff[j] << 8) + buff[j+1];
+    skip_bignum (buff, l, j, &j, 3);
+  else if (alg == 16 || alg == 20)
+    skip_bignum (buff, l, j, &j, 2);
+
+  len = (buff[j] << 8) + buff[j + 1];
   p->keylen = len;
 
-  if (alg >=1 && alg <= 3)
-    skip_bignum(buff, l, j, &j, 2);
-  else if(alg == 17 || alg == 16)
-    skip_bignum(buff, l, j, &j, 1);
-  
-  pgp_make_pgp3_fingerprint(buff, j, digest);
+  if (alg >= 1 && alg <= 3)
+    skip_bignum (buff, l, j, &j, 2);
+  else if (alg == 17 || alg == 16)
+    skip_bignum (buff, l, j, &j, 1);
+
+  pgp_make_pgp3_fingerprint (buff, j, digest);
 
-  for(k = 0; k < 2; k++)
+  for (k = 0; k < 2; k++)
   {
-    for(id = 0, i = SHA_DIGEST_LENGTH - 8 + k*4; 
-       i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++)
+    for (id = 0, i = SHA_DIGEST_LENGTH - 8 + k * 4;
+        i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++)
       id = (id << 8) + digest[i];
-  
-    snprintf((char *)scratch + k * 8, sizeof(scratch) - k * 8, "%08lX", id);
+
+    snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, "%08lX", id);
   }
-  
-  p->keyid = safe_strdup((char *)scratch);
-  
+
+  p->keyid = safe_strdup ((char *) scratch);
+
   return p;
 }
 
-static KEYINFO *pgp_parse_keyinfo(unsigned char *buff, size_t l)
+static pgp_key_t *pgp_parse_keyinfo (unsigned char *buff, size_t l)
 {
-  if(!buff || l < 2)
+  if (!buff || l < 2)
     return NULL;
 
   dprint (5, (debugfile, " version: %d ", buff[1]));
-  
-  switch(buff[1])
+
+  switch (buff[1])
   {
-    case 2:
-    case 3:
-      return pgp_parse_pgp2_key(buff, l);
-    case 4:
-      return pgp_parse_pgp3_key(buff, l);
-    default:
-      return NULL;
+  case 2:
+  case 3:
+    return pgp_parse_pgp2_key (buff, l);
+  case 4:
+    return pgp_parse_pgp3_key (buff, l);
+  default:
+    return NULL;
   }
 }
 
-static int pgp_parse_pgp2_sig(unsigned char *buff, size_t l, KEYINFO *p)
+static int pgp_parse_pgp2_sig (unsigned char *buff, size_t l, pgp_key_t * p)
 {
   unsigned char sigtype;
   long sig_gen_time;
   unsigned long signerid;
   size_t j;
   int i;
-  
-  if(l < 22)
+
+  if (l < 22)
     return -1;
-         
+
   j = 3;
   sigtype = buff[j++];
-         
+
   sig_gen_time = 0;
-  for(i = 0; i < 4; i++)
+  for (i = 0; i < 4; i++)
     sig_gen_time = (sig_gen_time << 8) + buff[j++];
-  
+
   j += 4;
   signerid = 0;
-  for(i = 0; i < 4; i++)
+  for (i = 0; i < 4; i++)
     signerid = (signerid << 8) + buff[j++];
-  
-  if(sigtype == 0x20 || sigtype == 0x28)
+
+  if (sigtype == 0x20 || sigtype == 0x28)
     p->flags |= KEYFLAG_REVOKED;
-  
+
   return 0;
 }
 
-static int pgp_parse_pgp3_sig(unsigned char *buff, size_t l, KEYINFO *p)
+static int pgp_parse_pgp3_sig (unsigned char *buff, size_t l, pgp_key_t * p)
 {
   unsigned char sigtype;
   unsigned char pkalg;
@@ -588,228 +704,226 @@ static int pgp_parse_pgp3_sig(unsigned char *buff, size_t l, KEYINFO *p)
   size_t j;
   int i;
   short ii;
-  short have_critical_spks=0;
-  
-  if(l < 7)
+  short have_critical_spks = 0;
+
+  if (l < 7)
     return -1;
-  
+
   j = 2;
-  
+
   sigtype = buff[j++];
   pkalg = buff[j++];
   hashalg = buff[j++];
-  
-  for(ii = 0; ii < 2; ii++)
+
+  for (ii = 0; ii < 2; ii++)
   {
     size_t skl;
     size_t nextone;
-    
-    ml = (buff[j] << 8) + buff[j+1];
+
+    ml = (buff[j] << 8) + buff[j + 1];
     j += 2;
-    
-    if(j + ml > l) break;
-    
+
+    if (j + ml > l)
+      break;
+
     nextone = j;
-    while(ml)
+    while (ml)
     {
       j = nextone;
       skl = buff[j++];
-      if(!--ml) break;
-      
-      if(skl >= 192)
+      if (!--ml)
+       break;
+
+      if (skl >= 192)
       {
        skl = (skl - 192) * 256 + buff[j++] + 192;
-       if(!--ml) break;
+       if (!--ml)
+         break;
       }
-      
-      if((int) ml - (int) skl < 0)
+
+      if ((int) ml - (int) skl < 0)
        break;
       ml -= skl;
-      
+
       nextone = j + skl;
       skt = buff[j++];
-      
-      switch(skt & 0x7f)
+
+      switch (skt & 0x7f)
       {
-       case 2: /* creation time */ 
+       case 2:                 /* creation time */
        {
-         if(skl < 4)
+         if (skl < 4)
            break;
          sig_gen_time = 0;
-         for(i = 0; i < 4; i++)
+         for (i = 0; i < 4; i++)
            sig_gen_time = (sig_gen_time << 8) + buff[j++];
-         
+
          break;
        }
-       case 3: /* expiration time */ 
+       case 3:                 /* expiration time */
        {
-         if(skl < 4)
+         if (skl < 4)
            break;
          validity = 0;
-         for(i = 0; i < 4; i++)
+         for (i = 0; i < 4; i++)
            validity = (validity << 8) + buff[j++];
          break;
        }
-       case 9: /* key expiration time */ 
+       case 9:                 /* key expiration time */
        {
-         if(skl < 4)
+         if (skl < 4)
            break;
          key_validity = 0;
-         for(i = 0; i < 4; i++)
+         for (i = 0; i < 4; i++)
            key_validity = (key_validity << 8) + buff[j++];
          break;
        }
-       case 16: /* issuer key ID */
+       case 16:                        /* issuer key ID */
        {
-         if(skl < 8)
+         if (skl < 8)
            break;
          j += 4;
          signerid = 0;
-         for(i = 0; i < 4; i++)
+         for (i = 0; i < 4; i++)
            signerid = (signerid << 8) + buff[j++];
          break;
        }
-       case 10: /* CMR key */  break;
-       case 4: /* exportable */ 
-       case 5: /* trust */
-       case 6: /* regexp */
-       case 7: /* revocable */
-       case 11: /* Pref. symm. alg. */
-       case 12: /* revocation key */
-       case 20: /* notation data */
-       case 21: /* pref. hash */ 
-       case 22: /* pref. comp.alg. */
-       case 23: /* key server prefs. */ 
-       case 24: /* pref. key server */ 
+       case 10:                        /* CMR key */
+       break;
+       case 4:                         /* exportable */
+       case 5:                         /* trust */
+       case 6:                         /* regexp */
+       case 7:                         /* revocable */
+       case 11:                        /* Pref. symm. alg. */
+       case 12:                        /* revocation key */
+       case 20:                        /* notation data */
+       case 21:                        /* pref. hash */
+       case 22:                        /* pref. comp.alg. */
+       case 23:                        /* key server prefs. */
+       case 24:                        /* pref. key server */
        default:
        {
-         if(skt & 0x80)
+         if (skt & 0x80)
            have_critical_spks = 1;
        }
       }
     }
     j = nextone;
   }
-  
-  if(sigtype == 0x20 || sigtype == 0x28)
+
+  if (sigtype == 0x20 || sigtype == 0x28)
     p->flags |= KEYFLAG_REVOKED;
-  if(key_validity != -1 && time(NULL) > p->gen_time + key_validity)
+  if (key_validity != -1 && time (NULL) > p->gen_time + key_validity)
     p->flags |= KEYFLAG_EXPIRED;
-  if(have_critical_spks)
+  if (have_critical_spks)
     p->flags |= KEYFLAG_CRITICAL;
 
   return 0;
-  
+
 }
-  
 
-static int pgp_parse_sig(unsigned char *buff, size_t l, KEYINFO *p)
+
+static int pgp_parse_sig (unsigned char *buff, size_t l, pgp_key_t * p)
 {
-  if(!buff || l < 2 || !p)
+  if (!buff || l < 2 || !p)
     return -1;
-  
-  switch(buff[1])
+
+  switch (buff[1])
   {
-    case 2:
-    case 3:
-      return pgp_parse_pgp2_sig(buff, l, p);
-    case 4:
-      return pgp_parse_pgp3_sig(buff, l, p);
-    default:
+  case 2:
+  case 3:
+    return pgp_parse_pgp2_sig (buff, l, p);
+  case 4:
+    return pgp_parse_pgp3_sig (buff, l, p);
+  default:
     return -1;
   }
 }
 
-  
-static KEYINFO *pgp_read_keyring(const char *fname)
+/* parse one key block, including all subkeys. */
+
+static pgp_key_t *pgp_parse_keyblock (FILE * fp)
 {
-  FILE *fp;
   unsigned char *buff;
   unsigned char pt = 0;
   unsigned char last_pt;
   size_t l;
-  KEYINFO *db = NULL, **end, *p = NULL;
-  KEYINFO *supkey = NULL;
-  PGPUID *uid = NULL;
-  LIST **addr = NULL;
-  CHARSET *chs = mutt_get_charset(Charset);
+  short err = 0;
+
+  fpos_t pos;
   
-  if(!(fp = fopen(fname, "r")))
-  {
-    mutt_perror("fopen");
-    return NULL;
-      
-  }
+  pgp_key_t *root = NULL;
+  pgp_key_t **last = &root;
+  pgp_key_t *p = NULL;
+  pgp_uid_t *uid = NULL;
+  pgp_uid_t **addr = NULL;
+  
+  CHARSET *chs = mutt_get_charset (Charset);
 
-  end = &db;
+  fgetpos (fp, &pos);
   
-  while((buff = pgp_read_packet(fp, &l)) != NULL)
+  while (!err && (buff = pgp_read_packet (fp, &l)) != NULL)
   {
     last_pt = pt;
     pt = buff[0] & 0x3f;
 
-    if(l < 1)
-      continue;
-
-    switch(pt)
+    /* check if we have read the complete key block. */
+    
+    if ((pt == PT_SECKEY || pt == PT_PUBKEY) && root)
+    {
+      fsetpos (fp, &pos);
+      return root;
+    }
+    
+    switch (pt)
     {
       case PT_SECKEY:
       case PT_PUBKEY:
       case PT_SUBKEY:
       case PT_SUBSECKEY:
       {
-       switch (pt)
+       if (!(*last = p = pgp_parse_keyinfo (buff, l)))
        {
-         case PT_SECKEY: dprint (5, (debugfile, "PT_SECKEY: ")); break;
-         case PT_PUBKEY: dprint (5, (debugfile, "PT_PUBKEY: ")); break;
-         case PT_SUBKEY: dprint (5, (debugfile, "PT_SUBKEY: ")); break;
-         case PT_SUBSECKEY: dprint (5, (debugfile, "PT_SUBSECKEY: ")); break;
+         err = 1;
+         break;
        }
 
-       if(p)
-         end = &(p->next);
-       
-       if(!(*end = p = pgp_parse_keyinfo(buff, l)))
-          break;
-
-       dprint (5, (debugfile, " key-id: %s ", p->keyid));
-       
+       last = &p->next;
        addr = &p->address;
-
-       if(pt == PT_SUBKEY || pt == PT_SUBSECKEY)
+       
+       if (pt == PT_SUBKEY || pt == PT_SUBSECKEY)
        {
          p->flags |= KEYFLAG_SUBKEY;
-         p->mainkey = supkey;
+         if (p != root)
+           p->parent = root;
        }
-       else
-         supkey = p;
-       
        break;
       }
-      
+
       case PT_SIG:
       {
        dprint (5, (debugfile, "PT_SIG\n"));
-       pgp_parse_sig(buff, l, p);
+       pgp_parse_sig (buff, l, p);
        break;
       }
+      
       case PT_TRUST:
       {
        dprint (5, (debugfile, "PT_TRUST: "));
-       if(last_pt == PT_SECKEY || last_pt == PT_PUBKEY ||
-          last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY)
+       if (p && (last_pt == PT_SECKEY || last_pt == PT_PUBKEY ||
+                 last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY))
        {
-         if(buff[1] & 0x20)
+         if (buff[1] & 0x20)
          {
            dprint (5, (debugfile, " disabling %s\n", p->keyid));
            p->flags |= KEYFLAG_DISABLED;
          }
        }
-       else if(last_pt == PT_NAME)
+       else if (last_pt == PT_NAME && uid)
        {
          uid->trust = buff[1];
-         dprint  (5, (debugfile, " setting trust for \"%s\" to %d.\n",
-                      uid->addr, uid->trust));
+         dprint (5, (debugfile, " setting trust for \"%s\" to %d.\n",
+                     uid->addr, uid->trust));
        }
        break;
       }
@@ -818,94 +932,142 @@ static KEYINFO *pgp_read_keyring(const char *fname)
        char *chr;
 
        dprint (5, (debugfile, "PT_NAME: "));
-       
-       if(!addr) break;
-       
-       chr = safe_malloc(l);
-       memcpy(chr, buff + 1, l - 1);
-       chr[l-1] = '\0';
-       
+
+       if (!addr)
+         break;
+
+       chr = safe_malloc (l);
+       memcpy (chr, buff + 1, l - 1);
+       chr[l - 1] = '\0';
+
        dprint (5, (debugfile, "\"%s\"\n", chr));
-       
-       mutt_decode_utf8_string(chr, chs);
-       *addr = mutt_new_list();
-       (*addr)->data = safe_malloc(sizeof(PGPUID));
-       uid = (PGPUID *) (*addr)->data;
+
+       mutt_decode_utf8_string (chr, chs);
+       *addr = uid = safe_calloc (sizeof (pgp_uid_t), 1); /* XXX */
        uid->addr = chr;
+       uid->parent = p;
        uid->trust = 0;
-       addr = &(*addr)->next;
-       
+       addr = &uid->next;
+
        /* the following tags are generated by
         * pgp 2.6.3in.
         */
-       
-       if(strstr(chr, "ENCR"))
+
+       if (strstr (chr, "ENCR"))
          p->flags |= KEYFLAG_PREFER_ENCRYPTION;
-       if(strstr(chr, "SIGN"))
+       if (strstr (chr, "SIGN"))
          p->flags |= KEYFLAG_PREFER_SIGNING;
-       
+
        break;
       }
     }
-  }
-  fclose(fp);
-  
-#ifdef DEBUG
-  if (debuglevel >= 4)
-  {
-    KEYINFO *dbp;
-    LIST *lp;
 
-    fprintf (debugfile, "\n\npgp_read_keyring: START KEYRING DUMP.\n");
-    
-    for (dbp = db; dbp; dbp = dbp->next)
-    {
-      fprintf (debugfile, "%s [len=%d, flags=%d]\n", dbp->keyid, dbp->keylen, dbp->flags);
-      for (lp = dbp->address; lp; lp=lp->next)
-      {
-       fprintf (debugfile, "  %s [%d]\n", ((PGPUID *)lp->data)->addr,
-                ((PGPUID *)lp->data)->trust);
-      }
-    }
-    
-    fprintf (debugfile, "\nEND KEYRING DUMP.\n\n");
+    fgetpos (fp, &pos);
   }
-#endif
+
+  if (err)
+    pgp_free_key (&root);
   
-  return db;
+  return root;  
 }
 
-KEYINFO *pgp_read_pubring(struct pgp_vinfo *pgp)
+int pgp_string_matches_hint (const char *s, LIST * hints)
 {
-  return pgp_read_keyring(NONULL(*pgp->pubring));
-}
+  if (!hints)
+    return 1;
 
-KEYINFO *pgp_read_secring(struct pgp_vinfo *pgp)
-{
-  return pgp_read_keyring(NONULL(*pgp->secring));
+  for (; hints; hints = hints->next)
+  {
+    if (mutt_stristr (s, (char *) hints->data) != NULL)
+      return 1;
+  }
+
+  return 0;
 }
 
-void pgp_close_keydb (KEYINFO **ki)
+/* Go through the key ring file and look for keys with
+ * matching IDs.
+ */
+
+pgp_key_t *pgp_get_candidates (struct pgp_vinfo * pgp, pgp_ring_t keyring,
+                              LIST * hints)
 {
-  KEYINFO *tmp, *k = *ki;
-  PGPUID *uid;
-  LIST *p, *q;
-  
-  while (k)
+  char *ringfile;
+  FILE *rfp;
+  fpos_t pos, keypos;
+
+  unsigned char *buff = NULL;
+  unsigned char pt = 0;
+  size_t l = 0;
+
+  CHARSET *chs = mutt_get_charset (Charset);
+
+  pgp_key_t *keys = NULL;
+  pgp_key_t **last = &keys;
+  short err = 0;
+
+  switch (keyring)
+  {
+    case PGP_PUBRING:
+      ringfile = *pgp->pubring;
+      break;
+    case PGP_SECRING:
+      ringfile = *pgp->secring;
+      break;
+    default:
+      return NULL;
+  }
+
+  if ((rfp = fopen (ringfile, "r")) == NULL)
+  {
+    mutt_perror ("fopen");
+    return NULL;
+  }
+
+  fgetpos (rfp, &pos);
+  fgetpos (rfp, &keypos);
+
+  while (!err && (buff = pgp_read_packet (rfp, &l)) != NULL)
   {
-    if (k->keyid) safe_free ((void **)&k->keyid);
-    for(q = k->address; q; q = p)
+    pt = buff[0] & 0x3f;
+    
+    if (l < 1)
+      continue;
+    
+    if ((pt == PT_SECKEY) || (pt == PT_PUBKEY))
+    {
+      keypos = pos;
+    }
+    else if (pt == PT_NAME)
     {
-      uid = (PGPUID *) q->data;
-      p = q->next;
+      char *tmp = safe_malloc (l);
 
-      safe_free((void **)&uid->addr);
-      safe_free((void **)&q->data);
-      safe_free((void **)&q);
+      memcpy (tmp, buff + 1, l - 1);
+      tmp[l - 1] = '\0';
+      mutt_decode_utf8_string (tmp, chs);
+
+      if (pgp_string_matches_hint (tmp, hints))
+      {
+       pgp_key_t *p;
+
+       fsetpos (rfp, &keypos);
+
+       /* Not bailing out here would lead us into an endless loop. */
+
+       if ((*last = pgp_parse_keyblock (rfp)) == NULL)
+         err = 1;
+
+       for (p = *last; p; p = p->next)
+         last = &p->next;
+      }
+
+      safe_free ((void **) &tmp);
     }
-    tmp = k;
-    k = k->next;
-    safe_free ((void **)&tmp);
+
+    fgetpos (rfp, &pos);
   }
-  *ki = NULL;
+
+  fclose (rfp);
+
+  return keys;
 }
index ea8240ac0f646b7a6fd0f1507d46cdedf97aad94..a5d18c6645bd5492ec68baadf09f3517a1928e5a 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -108,6 +108,8 @@ const char *mutt_attach_fmt (
        const char *elsestring,
        unsigned long data,
        format_flag flags);
+const char *mutt_stristr (const char *, const char *);
+
 
 char *mutt_charset_hook (const char *);
 char *mutt_expand_path (char *, size_t);