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