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