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