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