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