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