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