Nico Golde:
[apps/madmutt.git] / pgpkey.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
4  * Copyright (c) 1998,1999 Thomas Roessler <roessler@does-not-exist.org>
5  *
6  * This file is part of mutt-ng, see http://www.muttng.org/.
7  * It's licensed under the GNU General Public License,
8  * please see the file GPL in the top level source directory.
9  */
10
11 #if HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14
15 #include "mutt.h"
16 #include "mutt_curses.h"
17 #include "mutt_menu.h"
18 #include "mime.h"
19 #include "pgp.h"
20 #include "pager.h"
21 #include "sort.h"
22
23 #include "lib/mem.h"
24 #include "lib/intl.h"
25 #include "lib/str.h"
26 #include "lib/debug.h"
27
28 #include <string.h>
29 #include <ctype.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34
35 #include <locale.h>
36
37 #ifdef CRYPT_BACKEND_CLASSIC_PGP
38
39 struct pgp_cache {
40   char *what;
41   char *dflt;
42   struct pgp_cache *next;
43 };
44
45 static struct pgp_cache *id_defaults = NULL;
46
47 static char trust_flags[] = "?- +";
48
49 static char *pgp_key_abilities (int flags)
50 {
51   static char buff[3];
52
53   if (!(flags & KEYFLAG_CANENCRYPT))
54     buff[0] = '-';
55   else if (flags & KEYFLAG_PREFER_SIGNING)
56     buff[0] = '.';
57   else
58     buff[0] = 'e';
59
60   if (!(flags & KEYFLAG_CANSIGN))
61     buff[1] = '-';
62   else if (flags & KEYFLAG_PREFER_ENCRYPTION)
63     buff[1] = '.';
64   else
65     buff[1] = 's';
66
67   buff[2] = '\0';
68
69   return buff;
70 }
71
72 static char pgp_flags (int flags)
73 {
74   if (flags & KEYFLAG_REVOKED)
75     return 'R';
76   else if (flags & KEYFLAG_EXPIRED)
77     return 'X';
78   else if (flags & KEYFLAG_DISABLED)
79     return 'd';
80   else if (flags & KEYFLAG_CRITICAL)
81     return 'c';
82   else
83     return ' ';
84 }
85
86 static pgp_key_t pgp_principal_key (pgp_key_t key)
87 {
88   if (key->flags & KEYFLAG_SUBKEY && key->parent)
89     return key->parent;
90   else
91     return key;
92 }
93
94 /*
95  * Format an entry on the PGP key selection menu.
96  * 
97  * %n   number
98  * %k   key id          %K      key id of the principal key
99  * %u   user id
100  * %a   algorithm       %A      algorithm of the princ. key
101  * %l   length          %L      length of the princ. key
102  * %f   flags           %F      flags of the princ. key
103  * %c   capabilities    %C      capabilities of the princ. key
104  * %t   trust/validity of the key-uid association
105  * %[...] date of key using strftime(3)
106  */
107
108 typedef struct pgp_entry {
109   size_t num;
110   pgp_uid_t *uid;
111 } pgp_entry_t;
112
113 static const char *pgp_entry_fmt (char *dest,
114                                   size_t destlen,
115                                   char op,
116                                   const char *src,
117                                   const char *prefix,
118                                   const char *ifstring,
119                                   const char *elsestring,
120                                   unsigned long data, format_flag flags)
121 {
122   char fmt[16];
123   pgp_entry_t *entry;
124   pgp_uid_t *uid;
125   pgp_key_t key, pkey;
126   int kflags = 0;
127   int optional = (flags & M_FORMAT_OPTIONAL);
128
129   entry = (pgp_entry_t *) data;
130   uid = entry->uid;
131   key = uid->parent;
132   pkey = pgp_principal_key (key);
133
134   if (isupper ((unsigned char) op))
135     key = pkey;
136
137   kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS)
138     | uid->flags;
139
140   switch (ascii_tolower (op)) {
141   case '[':
142
143     {
144       const char *cp;
145       char buf2[SHORT_STRING], *p;
146       int do_locales;
147       struct tm *tm;
148       size_t len;
149
150       p = dest;
151
152       cp = src;
153       if (*cp == '!') {
154         do_locales = 0;
155         cp++;
156       }
157       else
158         do_locales = 1;
159
160       len = destlen - 1;
161       while (len > 0 && *cp != ']') {
162         if (*cp == '%') {
163           cp++;
164           if (len >= 2) {
165             *p++ = '%';
166             *p++ = *cp;
167             len -= 2;
168           }
169           else
170             break;              /* not enough space */
171           cp++;
172         }
173         else {
174           *p++ = *cp++;
175           len--;
176         }
177       }
178       *p = 0;
179
180       if (do_locales && Locale)
181         setlocale (LC_TIME, Locale);
182
183       tm = localtime (&key->gen_time);
184
185       strftime (buf2, sizeof (buf2), dest, tm);
186
187       if (do_locales)
188         setlocale (LC_TIME, "C");
189
190       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
191       snprintf (dest, destlen, fmt, buf2);
192       if (len > 0)
193         src = cp + 1;
194     }
195     break;
196   case 'n':
197     if (!optional) {
198       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
199       snprintf (dest, destlen, fmt, entry->num);
200     }
201     break;
202   case 'k':
203     if (!optional) {
204       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
205       snprintf (dest, destlen, fmt, _pgp_keyid (key));
206     }
207     break;
208   case 'u':
209     if (!optional) {
210       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
211       snprintf (dest, destlen, fmt, uid->addr);
212     }
213     break;
214   case 'a':
215     if (!optional) {
216       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
217       snprintf (dest, destlen, fmt, key->algorithm);
218     }
219     break;
220   case 'l':
221     if (!optional) {
222       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
223       snprintf (dest, destlen, fmt, key->keylen);
224     }
225     break;
226   case 'f':
227     if (!optional) {
228       snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
229       snprintf (dest, destlen, fmt, pgp_flags (kflags));
230     }
231     else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
232       optional = 0;
233     break;
234   case 'c':
235     if (!optional) {
236       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
237       snprintf (dest, destlen, fmt, pgp_key_abilities (kflags));
238     }
239     else if (!(kflags & (KEYFLAG_ABILITIES)))
240       optional = 0;
241     break;
242   case 't':
243     if (!optional) {
244       snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
245       snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]);
246     }
247     else if (!(uid->trust & 0x03))
248       /* undefined trust */
249       optional = 0;
250     break;
251   default:
252     *dest = '\0';
253   }
254
255   if (optional)
256     mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
257   else if (flags & M_FORMAT_OPTIONAL)
258     mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
259   return (src);
260 }
261
262 static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
263 {
264   pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
265   pgp_entry_t entry;
266
267   entry.uid = KeyTable[num];
268   entry.num = num + 1;
269
270   mutt_FormatString (s, l, NONULL (PgpEntryFormat), pgp_entry_fmt,
271                      (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
272 }
273
274 static int _pgp_compare_address (const void *a, const void *b)
275 {
276   int r;
277
278   pgp_uid_t **s = (pgp_uid_t **) a;
279   pgp_uid_t **t = (pgp_uid_t **) b;
280
281   if ((r = safe_strcasecmp ((*s)->addr, (*t)->addr)))
282     return r > 0;
283   else
284     return (safe_strcasecmp (_pgp_keyid ((*s)->parent),
285                              _pgp_keyid ((*t)->parent)) > 0);
286 }
287
288 static int pgp_compare_address (const void *a, const void *b)
289 {
290   return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b)
291           : _pgp_compare_address (a, b));
292 }
293
294
295
296 static int _pgp_compare_keyid (const void *a, const void *b)
297 {
298   int r;
299
300   pgp_uid_t **s = (pgp_uid_t **) a;
301   pgp_uid_t **t = (pgp_uid_t **) b;
302
303   if ((r = safe_strcasecmp (_pgp_keyid ((*s)->parent),
304                             _pgp_keyid ((*t)->parent))))
305     return r > 0;
306   else
307     return (safe_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
308 }
309
310 static int pgp_compare_keyid (const void *a, const void *b)
311 {
312   return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b)
313           : _pgp_compare_keyid (a, b));
314 }
315
316 static int _pgp_compare_date (const void *a, const void *b)
317 {
318   int r;
319   pgp_uid_t **s = (pgp_uid_t **) a;
320   pgp_uid_t **t = (pgp_uid_t **) b;
321
322   if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
323     return r > 0;
324   return (safe_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
325 }
326
327 static int pgp_compare_date (const void *a, const void *b)
328 {
329   return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b)
330           : _pgp_compare_date (a, b));
331 }
332
333 static int _pgp_compare_trust (const void *a, const void *b)
334 {
335   int r;
336
337   pgp_uid_t **s = (pgp_uid_t **) a;
338   pgp_uid_t **t = (pgp_uid_t **) b;
339
340   if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS))
341             - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS)))))
342     return r > 0;
343   if ((r = ((*s)->trust - (*t)->trust)))
344     return r < 0;
345   if ((r = ((*s)->parent->keylen - (*t)->parent->keylen)))
346     return r < 0;
347   if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
348     return r < 0;
349   if ((r = safe_strcasecmp ((*s)->addr, (*t)->addr)))
350     return r > 0;
351   return (safe_strcasecmp (_pgp_keyid ((*s)->parent),
352                            _pgp_keyid ((*t)->parent))) > 0;
353 }
354
355 static int pgp_compare_trust (const void *a, const void *b)
356 {
357   return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b)
358           : _pgp_compare_trust (a, b));
359 }
360
361 static int pgp_key_is_valid (pgp_key_t k)
362 {
363   pgp_key_t pk = pgp_principal_key (k);
364
365   if (k->flags & KEYFLAG_CANTUSE)
366     return 0;
367   if (pk->flags & KEYFLAG_CANTUSE)
368     return 0;
369
370   return 1;
371 }
372
373 static int pgp_id_is_strong (pgp_uid_t * uid)
374 {
375   if ((uid->trust & 3) < 3)
376     return 0;
377   /* else */
378   return 1;
379 }
380
381 static int pgp_id_is_valid (pgp_uid_t * uid)
382 {
383   if (!pgp_key_is_valid (uid->parent))
384     return 0;
385   if (uid->flags & KEYFLAG_CANTUSE)
386     return 0;
387   /* else */
388   return 1;
389 }
390
391 #define PGP_KV_VALID    1
392 #define PGP_KV_ADDR     2
393 #define PGP_KV_STRING   4
394 #define PGP_KV_STRONGID 8
395
396 #define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING)
397
398 static int pgp_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
399                                 pgp_uid_t * uid)
400 {
401   int rv = 0;
402
403   if (pgp_id_is_valid (uid))
404     rv |= PGP_KV_VALID;
405
406   if (pgp_id_is_strong (uid))
407     rv |= PGP_KV_STRONGID;
408
409   if (addr->mailbox && u_addr->mailbox
410       && safe_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
411     rv |= PGP_KV_ADDR;
412
413   if (addr->personal && u_addr->personal
414       && safe_strcasecmp (addr->personal, u_addr->personal) == 0)
415     rv |= PGP_KV_STRING;
416
417   return rv;
418 }
419
420 static pgp_key_t pgp_select_key (pgp_key_t keys, ADDRESS * p, const char *s)
421 {
422   int keymax;
423   pgp_uid_t **KeyTable;
424   MUTTMENU *menu;
425   int i, done = 0;
426   char helpstr[SHORT_STRING], buf[LONG_STRING], tmpbuf[STRING];
427   char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
428   FILE *fp, *devnull;
429   pid_t thepid;
430   pgp_key_t kp;
431   pgp_uid_t *a;
432   int (*f) (const void *, const void *);
433
434   int unusable = 0;
435
436   keymax = 0;
437   KeyTable = NULL;
438
439   for (i = 0, kp = keys; kp; kp = kp->next) {
440     if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) {
441       unusable = 1;
442       continue;
443     }
444
445     for (a = kp->address; a; a = a->next) {
446       if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) {
447         unusable = 1;
448         continue;
449       }
450
451       if (i == keymax) {
452         keymax += 5;
453         safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax);
454       }
455
456       KeyTable[i++] = a;
457     }
458   }
459
460   if (!i && unusable) {
461     mutt_error _("All matching keys are expired, revoked, or disabled.");
462
463     mutt_sleep (1);
464     return NULL;
465   }
466
467   switch (PgpSortKeys & SORT_MASK) {
468   case SORT_DATE:
469     f = pgp_compare_date;
470     break;
471   case SORT_KEYID:
472     f = pgp_compare_keyid;
473     break;
474   case SORT_ADDRESS:
475     f = pgp_compare_address;
476     break;
477   case SORT_TRUST:
478   default:
479     f = pgp_compare_trust;
480     break;
481   }
482   qsort (KeyTable, i, sizeof (pgp_uid_t *), f);
483
484   helpstr[0] = 0;
485   mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_PGP, OP_EXIT);
486   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
487   mutt_make_help (buf, sizeof (buf), _("Select  "), MENU_PGP,
488                   OP_GENERIC_SELECT_ENTRY);
489   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
490   mutt_make_help (buf, sizeof (buf), _("Check key  "), MENU_PGP,
491                   OP_VERIFY_KEY);
492   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
493   mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP);
494   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
495
496   menu = mutt_new_menu ();
497   menu->max = i;
498   menu->make_entry = pgp_entry;
499   menu->menu = MENU_PGP;
500   menu->help = helpstr;
501   menu->data = KeyTable;
502
503   if (p)
504     snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox);
505   else
506     snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s);
507
508
509   menu->title = buf;
510
511   kp = NULL;
512
513   mutt_clear_error ();
514
515   while (!done) {
516     switch (mutt_menuLoop (menu)) {
517
518     case OP_VERIFY_KEY:
519
520       mutt_mktemp (tempfile);
521       if ((devnull = fopen ("/dev/null", "w")) == NULL) {       /* __FOPEN_CHECKED__ */
522         mutt_perror (_("Can't open /dev/null"));
523
524         break;
525       }
526       if ((fp = safe_fopen (tempfile, "w")) == NULL) {
527         fclose (devnull);
528         mutt_perror (_("Can't create temporary file"));
529
530         break;
531       }
532
533       mutt_message _("Invoking PGP...");
534
535       snprintf (tmpbuf, sizeof (tmpbuf), "0x%s",
536                 pgp_keyid (pgp_principal_key
537                            (KeyTable[menu->current]->parent)));
538
539       if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1,
540                                            fileno (fp), fileno (devnull),
541                                            tmpbuf)) == -1) {
542         mutt_perror (_("Can't create filter"));
543
544         unlink (tempfile);
545         fclose (fp);
546         fclose (devnull);
547       }
548
549       mutt_wait_filter (thepid);
550       fclose (fp);
551       fclose (devnull);
552       mutt_clear_error ();
553       snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),
554                 pgp_keyid (pgp_principal_key
555                            (KeyTable[menu->current]->parent)));
556       mutt_do_pager (cmd, tempfile, 0, NULL);
557       menu->redraw = REDRAW_FULL;
558
559       break;
560
561     case OP_VIEW_ID:
562
563       mutt_message ("%s", KeyTable[menu->current]->addr);
564       break;
565
566     case OP_GENERIC_SELECT_ENTRY:
567
568
569       /* XXX make error reporting more verbose */
570
571       if (option (OPTPGPCHECKTRUST))
572         if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) {
573           mutt_error _("This key can't be used: expired/disabled/revoked.");
574
575           break;
576         }
577
578       if (option (OPTPGPCHECKTRUST) &&
579           (!pgp_id_is_valid (KeyTable[menu->current])
580            || !pgp_id_is_strong (KeyTable[menu->current]))) {
581         char *s = "";
582         char buff[LONG_STRING];
583
584         if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE)
585           s = N_("ID is expired/disabled/revoked.");
586         else
587           switch (KeyTable[menu->current]->trust & 0x03) {
588           case 0:
589             s = N_("ID has undefined validity.");
590             break;
591           case 1:
592             s = N_("ID is not valid.");
593             break;
594           case 2:
595             s = N_("ID is only marginally valid.");
596             break;
597           }
598
599         snprintf (buff, sizeof (buff),
600                   _("%s Do you really want to use the key?"), _(s));
601
602         if (mutt_yesorno (buff, M_NO) != M_YES) {
603           mutt_clear_error ();
604           break;
605         }
606       }
607
608 # if 0
609       kp = pgp_principal_key (KeyTable[menu->current]->parent);
610 # else
611       kp = KeyTable[menu->current]->parent;
612 # endif
613       done = 1;
614       break;
615
616     case OP_EXIT:
617
618       kp = NULL;
619       done = 1;
620       break;
621     }
622   }
623
624   mutt_menuDestroy (&menu);
625   FREE (&KeyTable);
626
627   set_option (OPTNEEDREDRAW);
628
629   return (kp);
630 }
631
632 pgp_key_t pgp_ask_for_key (char *tag, char *whatfor,
633                            short abilities, pgp_ring_t keyring)
634 {
635   pgp_key_t key;
636   char resp[SHORT_STRING];
637   struct pgp_cache *l = NULL;
638
639   mutt_clear_error ();
640
641   resp[0] = 0;
642   if (whatfor) {
643
644     for (l = id_defaults; l; l = l->next)
645       if (!safe_strcasecmp (whatfor, l->what)) {
646         strfcpy (resp, NONULL (l->dflt), sizeof (resp));
647         break;
648       }
649   }
650
651
652   FOREVER {
653     resp[0] = 0;
654     if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
655       return NULL;
656
657     if (whatfor) {
658       if (l)
659         str_replace (&l->dflt, resp);
660       else {
661         l = safe_malloc (sizeof (struct pgp_cache));
662         l->next = id_defaults;
663         id_defaults = l;
664         l->what = safe_strdup (whatfor);
665         l->dflt = safe_strdup (resp);
666       }
667     }
668
669     if ((key = pgp_getkeybystr (resp, abilities, keyring)))
670       return key;
671
672     BEEP ();
673   }
674   /* not reached */
675 }
676
677 /* generate a public key attachment */
678
679 BODY *pgp_make_key_attachment (char *tempf)
680 {
681   BODY *att;
682   char buff[LONG_STRING];
683   char tempfb[_POSIX_PATH_MAX], tmp[STRING];
684   FILE *tempfp;
685   FILE *devnull;
686   struct stat sb;
687   pid_t thepid;
688   pgp_key_t key;
689
690   unset_option (OPTPGPCHECKTRUST);
691
692   key =
693     pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
694
695   if (!key)
696     return NULL;
697
698   snprintf (tmp, sizeof (tmp), "0x%s", pgp_keyid (pgp_principal_key (key)));
699   pgp_free_key (&key);
700
701   if (!tempf) {
702     mutt_mktemp (tempfb);
703     tempf = tempfb;
704   }
705
706   if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) {
707     mutt_perror (_("Can't create temporary file"));
708
709     return NULL;
710   }
711
712   if ((devnull = fopen ("/dev/null", "w")) == NULL) {   /* __FOPEN_CHECKED__ */
713     mutt_perror (_("Can't open /dev/null"));
714
715     fclose (tempfp);
716     if (tempf == tempfb)
717       unlink (tempf);
718     return NULL;
719   }
720
721   mutt_message _("Invoking pgp...");
722
723
724   if ((thepid =
725        pgp_invoke_export (NULL, NULL, NULL, -1,
726                           fileno (tempfp), fileno (devnull), tmp)) == -1) {
727     mutt_perror (_("Can't create filter"));
728
729     unlink (tempf);
730     fclose (tempfp);
731     fclose (devnull);
732     return NULL;
733   }
734
735   mutt_wait_filter (thepid);
736
737   fclose (tempfp);
738   fclose (devnull);
739
740   att = mutt_new_body ();
741   att->filename = safe_strdup (tempf);
742   att->unlink = 1;
743   att->use_disp = 0;
744   att->type = TYPEAPPLICATION;
745   att->subtype = safe_strdup ("pgp-keys");
746   snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp);
747   att->description = safe_strdup (buff);
748   mutt_update_encoding (att);
749
750   stat (tempf, &sb);
751   att->length = sb.st_size;
752
753   return att;
754 }
755
756 static LIST *pgp_add_string_to_hints (LIST * hints, const char *str)
757 {
758   char *scratch;
759   char *t;
760
761   if ((scratch = safe_strdup (str)) == NULL)
762     return hints;
763
764   for (t = strtok (scratch, " ,.:\"()<>\n"); t;
765        t = strtok (NULL, " ,.:\"()<>\n")) {
766     if (mutt_strlen (t) > 3)
767       hints = mutt_add_list (hints, t);
768   }
769
770   FREE (&scratch);
771   return hints;
772 }
773
774 static pgp_key_t *pgp_get_lastp (pgp_key_t p)
775 {
776   for (; p; p = p->next)
777     if (!p->next)
778       return &p->next;
779
780   return NULL;
781 }
782
783 pgp_key_t pgp_getkeybyaddr (ADDRESS * a, short abilities, pgp_ring_t keyring)
784 {
785   ADDRESS *r, *p;
786   LIST *hints = NULL;
787
788   int weak = 0;
789   int invalid = 0;
790   int multi = 0;
791   int this_key_has_strong;
792   int this_key_has_weak;
793   int this_key_has_invalid;
794   int match;
795
796   pgp_key_t keys, k, kn;
797   pgp_key_t the_valid_key = NULL;
798   pgp_key_t matches = NULL;
799   pgp_key_t *last = &matches;
800   pgp_uid_t *q;
801
802   if (a && a->mailbox)
803     hints = pgp_add_string_to_hints (hints, a->mailbox);
804   if (a && a->personal)
805     hints = pgp_add_string_to_hints (hints, a->personal);
806
807   mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
808   keys = pgp_get_candidates (keyring, hints);
809
810   mutt_free_list (&hints);
811
812   if (!keys)
813     return NULL;
814
815   debug_print (5, ("looking for %s <%s>\n", a->personal, a->mailbox));
816
817   for (k = keys; k; k = kn) {
818     kn = k->next;
819
820     debug_print (5, ("  looking at key: %s\n", pgp_keyid (k)));
821
822     if (abilities && !(k->flags & abilities)) {
823       debug_print (5, ("  insufficient abilities: Has %x, want %x\n",
824                   k->flags, abilities));
825       continue;
826     }
827
828     this_key_has_weak = 0;      /* weak but valid match   */
829     this_key_has_invalid = 0;   /* invalid match          */
830     this_key_has_strong = 0;    /* strong and valid match */
831     match = 0;                  /* any match              */
832
833     for (q = k->address; q; q = q->next) {
834       r = rfc822_parse_adrlist (NULL, q->addr);
835
836       for (p = r; p; p = p->next) {
837         int validity = pgp_id_matches_addr (a, p, q);
838
839         if (validity & PGP_KV_MATCH)    /* something matches */
840           match = 1;
841
842         /* is this key a strong candidate? */
843         if ((validity & PGP_KV_VALID) && (validity & PGP_KV_STRONGID)
844             && (validity & PGP_KV_ADDR)) {
845           if (the_valid_key && the_valid_key != k)
846             multi = 1;
847           the_valid_key = k;
848           this_key_has_strong = 1;
849         }
850         else if ((validity & PGP_KV_MATCH) && !(validity & PGP_KV_VALID))
851           this_key_has_invalid = 1;
852         else if ((validity & PGP_KV_MATCH)
853                  && (!(validity & PGP_KV_STRONGID)
854                      || !(validity & PGP_KV_ADDR)))
855           this_key_has_weak = 1;
856       }
857
858       rfc822_free_address (&r);
859     }
860
861     if (match && !this_key_has_strong && this_key_has_invalid)
862       invalid = 1;
863     if (match && !this_key_has_strong && this_key_has_weak)
864       weak = 1;
865
866     if (match) {
867       *last = pgp_principal_key (k);
868       kn = pgp_remove_key (&keys, *last);
869       last = pgp_get_lastp (k);
870     }
871   }
872
873   pgp_free_key (&keys);
874
875   if (matches) {
876     if (the_valid_key && !multi /* && !weak 
877                                    && !(invalid && option (OPTPGPSHOWUNUSABLE)) */ ) {
878       /*
879        * There was precisely one strong match on a valid ID.
880        * 
881        * Proceed without asking the user.
882        */
883       pgp_remove_key (&matches, the_valid_key);
884       pgp_free_key (&matches);
885       k = the_valid_key;
886     }
887     else {
888       /* 
889        * Else: Ask the user.
890        */
891       if ((k = pgp_select_key (matches, a, NULL)))
892         pgp_remove_key (&matches, k);
893       pgp_free_key (&matches);
894     }
895
896     return k;
897   }
898
899   return NULL;
900 }
901
902 pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring)
903 {
904   LIST *hints = NULL;
905   pgp_key_t keys;
906   pgp_key_t matches = NULL;
907   pgp_key_t *last = &matches;
908   pgp_key_t k, kn;
909   pgp_uid_t *a;
910   short match;
911
912   mutt_message (_("Looking for keys matching \"%s\"..."), p);
913
914   hints = pgp_add_string_to_hints (hints, p);
915   keys = pgp_get_candidates (keyring, hints);
916   mutt_free_list (&hints);
917
918   if (!keys)
919     return NULL;
920
921
922   for (k = keys; k; k = kn) {
923     kn = k->next;
924     if (abilities && !(k->flags & abilities))
925       continue;
926
927     match = 0;
928
929     for (a = k->address; a; a = a->next) {
930       debug_print (5, ("matching \"%s\" against key %s, \"%s\":\n", p, pgp_keyid (k), a->addr));
931       if (!*p || safe_strcasecmp (p, pgp_keyid (k)) == 0
932           || (!safe_strncasecmp (p, "0x", 2)
933               && !safe_strcasecmp (p + 2, pgp_keyid (k)))
934           || (option (OPTPGPLONGIDS) && !safe_strncasecmp (p, "0x", 2)
935               && !safe_strcasecmp (p + 2, k->keyid + 8))
936           || str_isstr (a->addr, p)) {
937         debug_print (5, ("match.\n"));
938         match = 1;
939         break;
940       }
941     }
942
943     if (match) {
944       *last = pgp_principal_key (k);
945       kn = pgp_remove_key (&keys, *last);
946       last = pgp_get_lastp (k);
947     }
948   }
949
950   pgp_free_key (&keys);
951
952   if (matches) {
953     if ((k = pgp_select_key (matches, NULL, p)))
954       pgp_remove_key (&matches, k);
955
956     pgp_free_key (&matches);
957     return k;
958   }
959
960   return NULL;
961 }
962
963
964
965 #endif /* CRYPT_BACKEND_CLASSIC_PGP */