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