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