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