2 * Copyright notice from original mutt:
3 * crypt-gpgme.c - GPGME based crypto operations
4 * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
5 * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
6 * Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
7 * Oliver Ehli <elmy@acm.org>
8 * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
15 #include <lib-lib/lib-lib.h>
20 #ifdef HAVE_LANGINFO_D_T_FMT
21 # include <langinfo.h>
23 #ifdef HAVE_SYS_RESOURCE_H
24 # include <sys/resource.h>
29 #include <lib-mime/mime.h>
31 #include <lib-ui/curses.h>
32 #include <lib-ui/enter.h>
33 #include <lib-ui/menu.h>
37 #include <lib-crypt/crypt.h>
41 #include "recvattach.h"
43 #include "crypt-gpgme.h"
48 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
49 #define hexdigitp(a) (digitp (a) \
50 || (*(a) >= 'A' && *(a) <= 'F') \
51 || (*(a) >= 'a' && *(a) <= 'f'))
52 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
53 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
54 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
56 /* Values used for comparing addresses. */
57 #define CRYPT_KV_VALID 1
58 #define CRYPT_KV_ADDR 2
59 #define CRYPT_KV_STRING 4
60 #define CRYPT_KV_STRONGID 8
61 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
70 struct crypt_cache *next;
78 /* We work based on user IDs, getting from a user ID to the key is
79 check and does not need any memory (gpgme uses reference counting). */
80 typedef struct crypt_keyinfo {
81 struct crypt_keyinfo *next;
83 int idx; /* and the user ID at this index */
84 const char *uid; /* and for convenience point to this user ID */
85 unsigned int flags; /* global and per uid flags (for convenience) */
88 typedef struct crypt_entry {
94 static struct crypt_cache *id_defaults = NULL;
95 static gpgme_key_t signature_key = NULL;
98 * General helper functions.
101 /* return true when S points to a didgit or letter. */
102 static int digit_or_letter (const unsigned char *s)
104 return ((*s >= '0' && *s <= '9')
105 || (*s >= 'A' && *s <= 'Z')
106 || (*s >= 'a' && *s <= 'z'));
110 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
111 FP. Convert the character set. */
112 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
116 tstr = p_dupstr(buf, len);
117 mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
127 /* Return the keyID for the key K. Note that this string is valid as
128 long as K is valid */
129 static const char *crypt_keyid (crypt_key_t * k)
131 const char *s = "????????";
133 if (k->kobj && k->kobj->subkeys) {
134 s = k->kobj->subkeys->keyid;
135 if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
136 /* Return only the short keyID. */
143 /* Return the hexstring fingerprint from the key K. */
144 static const char *crypt_fpr (crypt_key_t * k)
148 if (k->kobj && k->kobj->subkeys)
149 s = k->kobj->subkeys->fpr;
154 /* Parse FLAGS and return a statically allocated(!) string with them. */
155 static char *crypt_key_abilities (int flags)
159 if (!(flags & KEYFLAG_CANENCRYPT))
161 else if (flags & KEYFLAG_PREFER_SIGNING)
166 if (!(flags & KEYFLAG_CANSIGN))
168 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
178 /* Parse FLAGS and return a character describing the most important flag. */
179 static char crypt_flags (int flags)
181 if (flags & KEYFLAG_REVOKED)
183 else if (flags & KEYFLAG_EXPIRED)
185 else if (flags & KEYFLAG_DISABLED)
187 else if (flags & KEYFLAG_CRITICAL)
193 /* Return a copy of KEY. */
194 static crypt_key_t *crypt_copy_key (crypt_key_t *key)
198 k = p_new(crypt_key_t, 1);
200 gpgme_key_ref (key->kobj);
203 k->flags = key->flags;
208 /* Release all the keys at the address of KEYLIST and set the address
210 static void crypt_free_key (crypt_key_t ** keylist)
213 crypt_key_t *k = (*keylist)->next;
220 /* Return trute when key K is valid. */
221 static int crypt_key_is_valid (crypt_key_t * k)
223 if (k->flags & KEYFLAG_CANTUSE)
228 /* Return true whe validity of KEY is sufficient. */
229 static int crypt_id_is_strong (crypt_key_t * key)
231 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
232 gpgme_user_id_t uid = NULL;
236 if ((key->flags & KEYFLAG_ISX509))
239 for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
240 i++, uid = uid->next);
245 case GPGME_VALIDITY_UNKNOWN:
246 case GPGME_VALIDITY_UNDEFINED:
247 case GPGME_VALIDITY_NEVER:
248 case GPGME_VALIDITY_MARGINAL:
252 case GPGME_VALIDITY_FULL:
253 case GPGME_VALIDITY_ULTIMATE:
261 /* Return true when the KEY is valid, i.e. not marked as unusable. */
262 static int crypt_id_is_valid (crypt_key_t * key)
264 return !(key->flags & KEYFLAG_CANTUSE);
267 /* Return a bit vector describing how well the addresses ADDR and
268 U_ADDR match and whether KEY is valid. */
269 static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
274 if (crypt_id_is_valid (key))
275 rv |= CRYPT_KV_VALID;
277 if (crypt_id_is_strong (key))
278 rv |= CRYPT_KV_STRONGID;
280 if (addr->mailbox && u_addr->mailbox
281 && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
284 if (addr->personal && u_addr->personal
285 && m_strcasecmp(addr->personal, u_addr->personal) == 0)
286 rv |= CRYPT_KV_STRING;
293 * GPGME convenient functions.
296 /* Create a new gpgme context and return it. With FOR_SMIME set to
297 true, the protocol of the context is set to CMS. */
298 static gpgme_ctx_t create_gpgme_context (int for_smime)
303 err = gpgme_new (&ctx);
305 mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
311 err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
313 mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
322 /* Create a new gpgme data object. This is a wrapper to die on
324 static gpgme_data_t create_gpgme_data (void)
329 err = gpgme_data_new (&data);
331 mutt_error (_("error creating gpgme data object: %s\n"),
332 gpgme_strerror (err));
339 /* Create a new GPGME Data object from the mail body A. With CONVERT
340 passed as true, the lines are converted to CR,LF if required.
341 Return NULL on error or the gpgme_data_t object on success. */
342 static gpgme_data_t body_to_data_object (BODY * a, int convert)
344 char tempfile[_POSIX_PATH_MAX];
349 fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
351 mutt_perror (_("Can't create temporary file"));
355 mutt_write_mime_header (a, fptmp);
357 mutt_write_mime_body (a, fptmp);
361 unsigned char buf[1];
363 data = create_gpgme_data ();
365 while ((c = fgetc (fptmp)) != EOF) {
369 if (c == '\n' && !hadcr) {
371 gpgme_data_write (data, buf, 1);
376 /* FIXME: This is quite suboptimal */
378 gpgme_data_write (data, buf, 1);
380 gpgme_data_seek (data, 0, SEEK_SET);
382 err = gpgme_data_new_from_file (&data, tempfile, 1);
387 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
394 /* Create a GPGME data object from the stream FP but limit the object
395 to LENGTH bytes starting at OFFSET bytes from the beginning of the
397 static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
402 err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
404 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
411 /* Write a GPGME data object to the stream FP. */
412 static int data_object_to_stream (gpgme_data_t data, FILE * fp)
418 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
419 ? gpgme_error_from_errno (errno) : 0);
421 mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
425 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
426 /* fixme: we are not really converting CRLF to LF but just
427 skipping CR. Doing it correctly needs a more complex logic */
428 for (p = buf; nread; p++, nread--) {
434 mutt_perror ("[tempfile]");
439 mutt_error (_("error reading data object: %s\n"), strerror (errno));
445 /* Copy a data object to a newly created temporay file and return that
446 filename. Caller must free. With RET_FP not NULL, don't close the
447 stream but return it there. */
448 static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
451 char tempfile[_POSIX_PATH_MAX];
455 fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
457 mutt_perror (_("Can't create temporary file"));
461 err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
462 ? gpgme_error_from_errno (errno) : 0);
466 while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
467 if (fwrite (buf, nread, 1, fp) != 1) {
468 mutt_perror (_("Can't create temporary file"));
480 mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
487 return m_strdup(tempfile);
491 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
492 The keys must be space delimited. */
493 static gpgme_key_t *create_recipient_set (const char *keylist,
494 gpgme_protocol_t protocol)
500 gpgme_key_t *rset = NULL;
501 unsigned int rset_n = 0;
502 gpgme_key_t key = NULL;
503 gpgme_ctx_t context = NULL;
505 err = gpgme_new (&context);
507 err = gpgme_set_protocol (context, protocol);
514 for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
518 if (i > 1 && buf[i - 1] == '!') {
519 /* The user selected to override the valididy of that
523 err = gpgme_get_key (context, buf, &key, 0);
525 key->uids->validity = GPGME_VALIDITY_FULL;
529 err = gpgme_get_key (context, buf, &key, 0);
532 p_realloc(&rset, rset_n + 1);
533 rset[rset_n++] = key;
536 mutt_error (_("error adding recipient `%s': %s\n"),
537 buf, gpgme_strerror (err));
545 /* NULL terminate. */
546 p_realloc(&rset, rset_n + 1);
547 rset[rset_n++] = NULL;
550 gpgme_release (context);
556 /* Make sure that the correct signer is set. Returns 0 on success. */
557 static int set_signer (gpgme_ctx_t ctx, int for_smime)
559 char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
562 gpgme_key_t key, key2;
564 if (!signid || !*signid)
567 listctx = create_gpgme_context (for_smime);
568 err = gpgme_op_keylist_start (listctx, signid, 1);
570 err = gpgme_op_keylist_next (listctx, &key);
572 gpgme_release (listctx);
573 mutt_error (_("secret key `%s' not found: %s\n"),
574 signid, gpgme_strerror (err));
577 err = gpgme_op_keylist_next (listctx, &key2);
579 gpgme_key_release (key);
580 gpgme_key_release (key2);
581 gpgme_release (listctx);
582 mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
585 gpgme_op_keylist_end (listctx);
586 gpgme_release (listctx);
588 gpgme_signers_clear (ctx);
589 err = gpgme_signers_add (ctx, key);
590 gpgme_key_release (key);
592 mutt_error (_("error setting secret key `%s': %s\n"),
593 signid, gpgme_strerror (err));
600 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
601 and return an allocated filename to a temporary file containing the
602 enciphered text. With USE_SMIME set to true, the smime backend is
603 used. With COMBINED_SIGNED a PGP message is signed and
604 encrypted. Returns NULL in case of error */
605 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
606 int use_smime, int combined_signed)
610 gpgme_data_t ciphertext;
613 ctx = create_gpgme_context (use_smime);
615 gpgme_set_armor (ctx, 1);
617 ciphertext = create_gpgme_data ();
619 if (combined_signed) {
620 if (set_signer (ctx, use_smime)) {
621 gpgme_data_release (ciphertext);
625 err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
626 plaintext, ciphertext);
629 err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
630 plaintext, ciphertext);
631 mutt_need_hard_redraw ();
633 mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
634 gpgme_data_release (ciphertext);
641 outfile = data_object_to_tempfile (ciphertext, NULL);
642 gpgme_data_release (ciphertext);
646 /* Find the "micalg" parameter from the last Gpgme operation on
647 context CTX. It is expected that this operation was a sign
648 operation. Return the algorithm name as a C string in buffer BUF
649 which must have been allocated by the caller with size BUFLEN.
650 Returns 0 on success or -1 in case of an error. The return string
651 is truncted to BUFLEN - 1. */
652 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
654 gpgme_sign_result_t result = NULL;
655 const char *algorithm_name = NULL;
661 result = gpgme_op_sign_result (ctx);
663 algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
664 if (algorithm_name) {
665 m_strcpy(buf, buflen, algorithm_name);
669 return *buf ? 0 : -1;
672 static void print_time (time_t t, STATE * s)
676 setlocale (LC_TIME, "");
677 #ifdef HAVE_LANGINFO_D_T_FMT
678 strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
680 strftime (p, sizeof (p), "%c", localtime (&t));
682 setlocale (LC_TIME, "C");
683 state_attach_puts (p, s);
687 * Implementation of `sign_message'.
690 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
691 USE_SMIME is passed as true. Returns the new body or NULL on
693 static BODY *sign_message (BODY * a, int use_smime)
700 gpgme_data_t message, signature;
702 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
704 message = body_to_data_object (a, 1);
707 signature = create_gpgme_data ();
709 ctx = create_gpgme_context (use_smime);
711 gpgme_set_armor (ctx, 1);
713 if (set_signer (ctx, use_smime)) {
714 gpgme_data_release (signature);
719 err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
720 mutt_need_hard_redraw ();
721 gpgme_data_release (message);
723 gpgme_data_release (signature);
725 mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
729 sigfile = data_object_to_tempfile (signature, NULL);
730 gpgme_data_release (signature);
737 t->type = TYPEMULTIPART;
738 t->subtype = m_strdup("signed");
739 t->encoding = ENC7BIT;
741 t->disposition = DISPINLINE;
743 parameter_set_boundary(&t->parameter);
744 parameter_setval(&t->parameter, "protocol",
745 use_smime ? "application/pkcs7-signature"
746 : "application/pgp-signature");
747 /* Get the micalg from gpgme. Old gpgme versions don't support this
748 for S/MIME so we assume sha-1 in this case. */
749 if (!get_micalg (ctx, buf, sizeof buf))
750 parameter_setval(&t->parameter, "micalg", buf);
752 parameter_setval(&t->parameter, "micalg", "sha1");
758 t->parts->next = body_new();
760 t->type = TYPEAPPLICATION;
762 t->subtype = m_strdup("pkcs7-signature");
763 parameter_setval(&t->parameter, "name", "smime.p7s");
764 t->encoding = ENCBASE64;
766 t->disposition = DISPATTACH;
767 t->d_filename = m_strdup("smime.p7s");
770 t->subtype = m_strdup("pgp-signature");
772 t->disposition = DISPINLINE;
773 t->encoding = ENC7BIT;
775 t->filename = sigfile;
776 t->unlink = 1; /* ok to remove this file after sending. */
782 BODY *pgp_gpgme_sign_message (BODY * a)
784 return sign_message (a, 0);
787 BODY *smime_gpgme_sign_message (BODY * a)
789 return sign_message (a, 1);
793 * Implementation of `encrypt_message'.
796 /* Encrypt the mail body A to all keys given as space separated keyids
797 or fingerprints in KEYLIST and return the encrypted body. */
798 BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
800 char *outfile = NULL;
802 gpgme_key_t *rset = NULL;
803 gpgme_data_t plaintext;
805 rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
811 plaintext = body_to_data_object (a, 0);
817 outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
818 gpgme_data_release (plaintext);
824 t->type = TYPEMULTIPART;
825 t->subtype = m_strdup("encrypted");
826 t->encoding = ENC7BIT;
828 t->disposition = DISPINLINE;
830 parameter_set_boundary(&t->parameter);
831 parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
833 t->parts = body_new();
834 t->parts->type = TYPEAPPLICATION;
835 t->parts->subtype = m_strdup("pgp-encrypted");
836 t->parts->encoding = ENC7BIT;
838 t->parts->next = body_new();
839 t->parts->next->type = TYPEAPPLICATION;
840 t->parts->next->subtype = m_strdup("octet-stream");
841 t->parts->next->encoding = ENC7BIT;
842 t->parts->next->filename = outfile;
843 t->parts->next->use_disp = 1;
844 t->parts->next->disposition = DISPINLINE;
845 t->parts->next->unlink = 1; /* delete after sending the message */
846 t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
853 * Implementation of `smime_build_smime_entity'.
856 /* Encrypt the mail body A to all keys given as space separated
857 fingerprints in KEYLIST and return the S/MIME encrypted body. */
858 BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
860 char *outfile = NULL;
862 gpgme_key_t *rset = NULL;
863 gpgme_data_t plaintext;
865 rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
869 plaintext = body_to_data_object (a, 0);
875 outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
876 gpgme_data_release (plaintext);
882 t->type = TYPEAPPLICATION;
883 t->subtype = m_strdup("pkcs7-mime");
884 parameter_setval(&t->parameter, "name", "smime.p7m");
885 parameter_setval(&t->parameter, "smime-type", "enveloped-data");
886 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
888 t->disposition = DISPATTACH;
889 t->d_filename = m_strdup("smime.p7m");
890 t->filename = outfile;
891 t->unlink = 1; /*delete after sending the message */
900 * Implementation of `verify_one'.
903 /* Display the common attributes of the signature summary SUM.
904 Return 1 if there is is a severe warning.
906 static int show_sig_summary (unsigned long sum,
907 gpgme_ctx_t ctx, gpgme_key_t key, int idx,
912 if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
913 state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
917 if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
918 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
921 state_attach_puts (_("Warning: The key used to create the "
922 "signature expired at: "), s);
924 state_attach_puts ("\n", s);
927 state_attach_puts (_("Warning: At least one certification key "
928 "has expired\n"), s);
931 if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
932 gpgme_verify_result_t result;
933 gpgme_signature_t sig;
936 result = gpgme_op_verify_result (ctx);
938 for (sig = result->signatures, i = 0; sig && (i < idx);
939 sig = sig->next, i++);
941 state_attach_puts (_("Warning: The signature expired at: "), s);
942 print_time (sig ? sig->exp_timestamp : 0, s);
943 state_attach_puts ("\n", s);
946 if ((sum & GPGME_SIGSUM_KEY_MISSING))
947 state_attach_puts (_("Can't verify due to a missing "
948 "key or certificate\n"), s);
950 if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
951 state_attach_puts (_("The CRL is not available\n"), s);
955 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
956 state_attach_puts (_("Available CRL is too old\n"), s);
960 if ((sum & GPGME_SIGSUM_BAD_POLICY))
961 state_attach_puts (_("A policy requirement was not met\n"), s);
963 if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
964 const char *t0 = NULL, *t1 = NULL;
965 gpgme_verify_result_t result;
966 gpgme_signature_t sig;
969 state_attach_puts (_("A system error occurred"), s);
971 /* Try to figure out some more detailed system error information. */
972 result = gpgme_op_verify_result (ctx);
973 for (sig = result->signatures, i = 0; sig && (i < idx);
974 sig = sig->next, i++);
977 t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
981 state_attach_puts (": ", s);
983 state_attach_puts (t0, s);
984 if (t1 && !(t0 && !m_strcmp(t0, t1))) {
986 state_attach_puts (",", s);
987 state_attach_puts (t1, s);
990 state_attach_puts ("\n", s);
997 static void show_fingerprint (gpgme_key_t key, STATE * state)
1002 const char *prefix = _("Fingerprint: ");
1007 s = key->subkeys ? key->subkeys->fpr : NULL;
1010 is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1012 bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
1013 buf = p_new(char, bufsize);
1014 m_strcpy(buf, bufsize, prefix);
1015 p = buf + m_strlen(buf);
1016 if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
1017 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
1028 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
1031 *p++ = is_pgp ? ' ' : ':';
1032 if (is_pgp && i == 7)
1037 /* just in case print remaining odd digits */
1042 state_attach_puts (buf, state);
1046 /* Show the valididy of a key used for one signature. */
1047 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
1049 gpgme_verify_result_t result = NULL;
1050 gpgme_signature_t sig = NULL;
1051 const char *txt = NULL;
1053 result = gpgme_op_verify_result (ctx);
1055 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
1057 switch (sig ? sig->validity : 0) {
1058 case GPGME_VALIDITY_UNKNOWN:
1059 txt = _("WARNING: We have NO indication whether "
1060 "the key belongs to the person named " "as shown above\n");
1062 case GPGME_VALIDITY_UNDEFINED:
1064 case GPGME_VALIDITY_NEVER:
1065 txt = _("WARNING: The key does NOT BELONG to "
1066 "the person named as shown above\n");
1068 case GPGME_VALIDITY_MARGINAL:
1069 txt = _("WARNING: It is NOT certain that the key "
1070 "belongs to the person named as shown above\n");
1072 case GPGME_VALIDITY_FULL:
1073 case GPGME_VALIDITY_ULTIMATE:
1078 state_attach_puts (txt, s);
1081 /* Show information about one signature. This fucntion is called with
1082 the context CTX of a sucessful verification operation and the
1083 enumerator IDX which should start at 0 and incremete for each
1086 Return values are: 0 for normal procession, 1 for a bad signature,
1087 2 for a signature with a warning or -1 for no more signature. */
1088 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1091 const char *fpr, *uid;
1092 gpgme_key_t key = NULL;
1093 int i, anybad = 0, anywarn = 0;
1095 gpgme_user_id_t uids = NULL;
1096 gpgme_verify_result_t result;
1097 gpgme_signature_t sig;
1098 gpgme_error_t err = GPG_ERR_NO_ERROR;
1100 result = gpgme_op_verify_result (ctx);
1102 /* FIXME: this code should use a static variable and remember
1103 the current position in the list of signatures, IMHO.
1106 for (i = 0, sig = result->signatures; sig && (i < idx);
1107 i++, sig = sig->next);
1109 return -1; /* Signature not found. */
1111 if (signature_key) {
1112 gpgme_key_release (signature_key);
1113 signature_key = NULL;
1116 created = sig->timestamp;
1120 if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1123 err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
1125 uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1127 signature_key = key;
1130 key = NULL; /* Old gpgme versions did not set KEY to NULL on
1131 error. Do it here to avoid a double free. */
1135 if (!s || !s->fpout || !(s->flags & M_DISPLAY)); /* No state information so no way to print anything. */
1137 state_attach_puts (_("Error getting key information: "), s);
1138 state_attach_puts (gpg_strerror (err), s);
1139 state_attach_puts ("\n", s);
1142 else if ((sum & GPGME_SIGSUM_GREEN)) {
1143 state_attach_puts (_("Good signature from: "), s);
1144 state_attach_puts (uid, s);
1145 state_attach_puts ("\n", s);
1146 for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1148 /* Skip primary UID. */
1152 state_attach_puts (_(" aka: "), s);
1153 state_attach_puts (uids->uid, s);
1154 state_attach_puts ("\n", s);
1156 state_attach_puts (_(" created: "), s);
1157 print_time (created, s);
1158 state_attach_puts ("\n", s);
1159 if (show_sig_summary (sum, ctx, key, idx, s))
1161 show_one_sig_validity (ctx, idx, s);
1163 else if ((sum & GPGME_SIGSUM_RED)) {
1164 state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1165 state_attach_puts (uid, s);
1166 state_attach_puts ("\n", s);
1167 show_sig_summary (sum, ctx, key, idx, s);
1169 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good
1170 signature, so we display what a PGP user expects: The name,
1171 fingerprint and the key validity (which is neither fully or
1173 state_attach_puts (_("Good signature from: "), s);
1174 state_attach_puts (uid, s);
1175 state_attach_puts ("\n", s);
1176 state_attach_puts (_(" created: "), s);
1177 print_time (created, s);
1178 state_attach_puts ("\n", s);
1179 show_one_sig_validity (ctx, idx, s);
1180 show_fingerprint (key, s);
1181 if (show_sig_summary (sum, ctx, key, idx, s))
1184 else { /* can't decide (yellow) */
1186 state_attach_puts (_("Error checking signature"), s);
1187 state_attach_puts ("\n", s);
1188 show_sig_summary (sum, ctx, key, idx, s);
1191 if (key != signature_key)
1192 gpgme_key_release (key);
1195 return anybad ? 1 : anywarn ? 2 : 0;
1198 /* Do the actual verification step. With IS_SMIME set to true we
1199 assume S/MIME (surprise!) */
1200 static int verify_one (BODY * sigbdy, STATE * s,
1201 const char *tempfile, int is_smime)
1207 gpgme_data_t signature, message;
1209 signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1213 /* We need to tell gpgme about the encoding because the backend can't
1214 auto-detect plain base-64 encoding which is used by S/MIME. */
1216 gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1218 err = gpgme_data_new_from_file (&message, tempfile, 1);
1220 gpgme_data_release (signature);
1221 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1224 ctx = create_gpgme_context (is_smime);
1226 /* Note: We don't need a current time output because GPGME avoids
1227 such an attack by separating the meta information from the
1229 state_attach_puts (_("[-- Begin signature information --]\n"), s);
1231 err = gpgme_op_verify (ctx, signature, message, NULL);
1232 mutt_need_hard_redraw ();
1236 snprintf (buf, sizeof (buf) - 1,
1237 _("Error: verification failed: %s\n"), gpgme_strerror (err));
1238 state_attach_puts (buf, s);
1240 else { /* Verification succeeded, see what the result is. */
1244 if (signature_key) {
1245 gpgme_key_release (signature_key);
1246 signature_key = NULL;
1249 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1260 gpgme_verify_result_t result;
1261 gpgme_sig_notation_t notation;
1262 gpgme_signature_t sig;
1264 result = gpgme_op_verify_result (ctx);
1266 for (sig = result->signatures; sig; sig = sig->next) {
1267 if (sig->notations) {
1268 state_attach_puts ("*** Begin Notation (signature by: ", s);
1269 state_attach_puts (sig->fpr, s);
1270 state_attach_puts (") ***\n", s);
1271 for (notation = sig->notations; notation; notation = notation->next)
1273 if (notation->name) {
1274 state_attach_puts (notation->name, s);
1275 state_attach_puts ("=", s);
1277 if (notation->value) {
1278 state_attach_puts (notation->value, s);
1279 if (!(*notation->value
1280 && (notation->value[m_strlen(notation->value) - 1] ==
1282 state_attach_puts ("\n", s);
1285 state_attach_puts ("*** End Notation ***\n", s);
1291 gpgme_release (ctx);
1293 state_attach_puts (_("[-- End signature information --]\n\n"), s);
1295 return badsig ? 1 : anywarn ? 2 : 0;
1298 int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1300 return verify_one (sigbdy, s, tempfile, 0);
1303 int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1305 return verify_one (sigbdy, s, tempfile, 1);
1309 * Implementation of `decrypt_part'.
1312 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1313 IS_SMIME) with body A described further by state S. Write
1314 plaintext out to file FPOUT and return a new body. For PGP returns
1315 a flag in R_IS_SIGNED to indicate whether this is a combined
1316 encrypted and signed message, for S/MIME it returns true when it is
1317 not a encrypted but a signed message. */
1318 static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
1325 gpgme_data_t ciphertext, plaintext;
1326 int maybe_signed = 0;
1333 ctx = create_gpgme_context (is_smime);
1336 /* Make a data object from the body, create context etc. */
1337 ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1340 plaintext = create_gpgme_data ();
1342 /* Do the decryption or the verification in case of the S/MIME hack. */
1343 if ((!is_smime) || maybe_signed) {
1345 err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1346 else if (maybe_signed)
1347 err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1350 /* Check wether signatures have been verified. */
1351 gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1353 if (verify_result->signatures)
1358 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1359 gpgme_data_release (ciphertext);
1361 if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1362 /* Check whether this might be a signed message despite what
1363 the mime header told us. Retry then. gpgsm returns the
1364 error information "unsupported Algorithm '?'" but gpgme
1365 will not store this unknown algorithm, thus we test that
1366 it has not been set. */
1367 gpgme_decrypt_result_t result;
1369 result = gpgme_op_decrypt_result (ctx);
1370 if (!result->unsupported_algorithm) {
1372 gpgme_data_release (plaintext);
1376 mutt_need_hard_redraw ();
1377 if ((s->flags & M_DISPLAY)) {
1380 snprintf (buf, sizeof (buf) - 1,
1381 _("[-- Error: decryption failed: %s --]\n\n"),
1382 gpgme_strerror (err));
1383 state_attach_puts (buf, s);
1385 gpgme_data_release (plaintext);
1386 gpgme_release (ctx);
1389 mutt_need_hard_redraw ();
1391 /* Read the output from GPGME, and make sure to change CRLF to LF,
1392 otherwise read_mime_header has a hard time parsing the message. */
1393 if (data_object_to_stream (plaintext, fpout)) {
1394 gpgme_data_release (plaintext);
1395 gpgme_release (ctx);
1398 gpgme_data_release (plaintext);
1400 a->is_signed_data = 0;
1406 a->is_signed_data = 1;
1408 *r_is_signed = -1; /* A signature exists. */
1410 if ((s->flags & M_DISPLAY))
1411 state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1412 for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1418 if (!anybad && idx && r_is_signed && *r_is_signed)
1419 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1421 if ((s->flags & M_DISPLAY))
1422 state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1424 gpgme_release (ctx);
1429 tattach = mutt_read_mime_header (fpout, 0);
1432 * Need to set the length of this body part.
1434 fstat (fileno (fpout), &info);
1435 tattach->length = info.st_size - tattach->offset;
1437 tattach->warnsig = anywarn;
1439 /* See if we need to recurse on this MIME part. */
1440 mutt_parse_part (fpout, tattach);
1446 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1447 the stream in CUR and FPOUT. Returns 0 on success. */
1448 int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1450 char tempfile[_POSIX_PATH_MAX];
1452 BODY *first_part = b;
1455 first_part->goodsig = 0;
1456 first_part->warnsig = 0;
1458 if (!mutt_is_multipart_encrypted (b))
1461 if (!b->parts || !b->parts->next)
1468 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1470 mutt_perror (_("Can't create temporary file"));
1475 *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1478 first_part->goodsig = 1;
1480 return *cur ? 0 : -1;
1484 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1485 the stream in CUR and FPOUT. Returns 0 on success. */
1486 int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
1489 char tempfile[_POSIX_PATH_MAX];
1493 long saved_b_offset;
1494 ssize_t saved_b_length;
1497 if (!mutt_is_application_smime (b))
1503 /* Decode the body - we need to pass binary CMS to the
1504 backend. The backend allows for Base64 encoded data but it does
1505 not allow for QP which I have seen in some messages. So better
1507 saved_b_type = b->type;
1508 saved_b_offset = b->offset;
1509 saved_b_length = b->length;
1512 fseeko (s.fpin, b->offset, 0);
1513 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1515 mutt_perror (_("Can't create temporary file"));
1518 mutt_unlink (tempfile);
1521 mutt_decode_attachment (b, &s);
1523 b->length = ftello (s.fpout);
1530 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1532 mutt_perror (_("Can't create temporary file"));
1535 mutt_unlink (tempfile);
1537 *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1539 (*cur)->goodsig = is_signed > 0;
1540 b->type = saved_b_type;
1541 b->length = saved_b_length;
1542 b->offset = saved_b_offset;
1545 if (*cur && !is_signed && !(*cur)->parts
1546 && mutt_is_application_smime (*cur)) {
1547 /* Assume that this is a opaque signed s/mime message. This is
1548 an ugly way of doing it but we have anyway a problem with
1549 arbitrary encoded S/MIME messages: Only the outer part may be
1550 encrypted. The entire mime parsing should be revamped,
1551 probably by keeping the temportary files so that we don't
1552 need to decrypt them all the time. Inner parts of an
1553 encrypted part can then pint into this file and tehre won't
1554 never be a need to decrypt again. This needs a partial
1555 rewrite of the MIME engine. */
1559 saved_b_type = bb->type;
1560 saved_b_offset = bb->offset;
1561 saved_b_length = bb->length;
1564 fseeko (s.fpin, bb->offset, 0);
1565 tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1567 mutt_perror (_("Can't create temporary file"));
1570 mutt_unlink (tempfile);
1573 mutt_decode_attachment (bb, &s);
1575 bb->length = ftello (s.fpout);
1583 *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1585 mutt_perror (_("Can't create temporary file"));
1588 mutt_unlink (tempfile);
1590 tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1592 tmp_b->goodsig = is_signed > 0;
1593 bb->type = saved_b_type;
1594 bb->length = saved_b_length;
1595 bb->offset = saved_b_offset;
1598 body_list_wipe(cur);
1601 return *cur ? 0 : -1;
1606 * Implementation of `pgp_check_traditional'.
1609 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
1612 char tempfile[_POSIX_PATH_MAX];
1613 char buf[HUGE_STRING];
1620 if (b->type != TYPETEXT)
1623 if (tagged_only && !b->tagged)
1626 tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1627 if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1632 if ((tfp = fopen(tempfile, "r")) == NULL) {
1637 while (fgets (buf, sizeof (buf), tfp)) {
1638 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1639 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1641 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1651 /* fix the content type */
1653 parameter_setval(&b->parameter, "format", "fixed");
1654 parameter_setval(&b->parameter, "x-action",
1655 enc ? "pgp-encrypted" : "pgp-signed");
1659 int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
1664 for (; b; b = b->next) {
1665 if (is_multipart (b))
1666 rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
1667 else if (b->type == TYPETEXT) {
1668 if ((r = mutt_is_application_pgp (b)))
1671 rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1679 * Implementation of `application_handler'.
1683 Copy a clearsigned message, and strip the signature and PGP's
1686 XXX - charset handling: We assume that it is safe to do
1687 character set decoding first, dash decoding second here, while
1688 we do it the other way around in the main handler.
1690 (Note that we aren't worse than Outlook & Cie in this, and also
1691 note that we can successfully handle anything produced by any
1692 existing versions of mutt.) */
1694 static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
1696 char buf[HUGE_STRING];
1697 short complete, armor_header;
1702 fname = data_object_to_tempfile (data, &fp);
1708 fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1710 for (complete = 1, armor_header = 1;
1711 fgetconvs (buf, sizeof (buf), fc) != NULL;
1712 complete = strchr (buf, '\n') != NULL) {
1715 state_puts (buf, s);
1719 if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1729 state_puts (s->prefix, s);
1731 if (buf[0] == '-' && buf[1] == ' ')
1732 state_puts (buf + 2, s);
1734 state_puts (buf, s);
1737 fgetconv_close (&fc);
1742 /* Support for classic_application/pgp */
1743 int pgp_gpgme_application_handler (BODY * m, STATE * s)
1745 int needpass = -1, pgp_keyblock = 0;
1749 off_t last_pos, offset;
1750 char buf[HUGE_STRING];
1751 FILE *pgpout = NULL;
1753 gpgme_error_t err = 0;
1754 gpgme_data_t armored_data = NULL;
1756 short maybe_goodsig = 1;
1757 short have_any_sigs = 0;
1759 char body_charset[STRING]; /* Only used for clearsigned messages. */
1761 /* For clearsigned messages we won't be able to get a character set
1762 but we know that this may only be text thus we assume Latin-1
1764 if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1765 m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1767 fseeko (s->fpin, m->offset, 0);
1768 last_pos = m->offset;
1770 for (bytes = m->length; bytes > 0;) {
1771 if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1774 offset = ftello (s->fpin);
1775 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1778 if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1780 start_pos = last_pos;
1782 if (!m_strcmp("MESSAGE-----\n", buf + 15))
1784 else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1788 else if (!option (OPTDONTHANDLEPGPKEYS) &&
1789 !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1794 /* XXX - we may wish to recode here */
1796 state_puts (s->prefix, s);
1797 state_puts (buf, s);
1801 have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1803 /* Copy PGP material to an data container */
1804 armored_data = create_gpgme_data ();
1805 gpgme_data_write (armored_data, buf, m_strlen(buf));
1806 while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1807 offset = ftello (s->fpin);
1808 bytes -= (offset - last_pos); /* don't rely on m_strlen(buf) */
1811 gpgme_data_write (armored_data, buf, m_strlen(buf));
1813 if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1815 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1816 || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1821 /* Invoke PGP if needed */
1822 if (!clearsign || (s->flags & M_VERIFY)) {
1823 unsigned int sig_stat = 0;
1824 gpgme_data_t plaintext;
1827 plaintext = create_gpgme_data ();
1828 ctx = create_gpgme_context (0);
1831 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1833 err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1834 if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1835 /* Decrypt verify can't handle signed only messages. */
1836 err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1837 ? gpgme_error_from_errno (errno) : 0;
1838 /* Must release plaintext so that we supply an
1839 uninitialized object. */
1840 gpgme_data_release (plaintext);
1841 plaintext = create_gpgme_data ();
1842 err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1849 snprintf (errbuf, sizeof (errbuf) - 1,
1850 _("Error: decryption/verification failed: %s\n"),
1851 gpgme_strerror (err));
1852 state_attach_puts (errbuf, s);
1854 else { /* Decryption/Verification succeeded */
1858 /* Check wether signatures have been verified. */
1859 gpgme_verify_result_t verify_result;
1861 verify_result = gpgme_op_verify_result (ctx);
1862 if (verify_result->signatures)
1868 if ((s->flags & M_DISPLAY) && sig_stat) {
1873 state_attach_puts (_("[-- Begin signature "
1874 "information --]\n"), s);
1877 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1886 state_attach_puts (_("[-- End signature "
1887 "information --]\n\n"), s);
1890 tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1893 state_attach_puts (_("Error: copy data failed\n"), s);
1897 p_delete(&tmpfname);
1900 gpgme_release (ctx);
1904 * Now, copy cleartext to the screen. NOTE - we expect that PGP
1905 * outputs utf-8 cleartext. This may not always be true, but it
1906 * seems to be a reasonable guess.
1909 if (s->flags & M_DISPLAY) {
1911 state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1912 else if (pgp_keyblock)
1913 state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1915 state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1919 copy_clearsigned (armored_data, s, body_charset);
1926 fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1927 while ((c = fgetconv (fc)) != EOF) {
1929 if (c == '\n' && s->prefix)
1930 state_puts (s->prefix, s);
1932 fgetconv_close (&fc);
1935 if (s->flags & M_DISPLAY) {
1936 state_putc ('\n', s);
1938 state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1939 else if (pgp_keyblock)
1940 state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1942 state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1950 /* XXX - we may wish to recode here */
1952 state_puts (s->prefix, s);
1953 state_puts (buf, s);
1957 m->goodsig = (maybe_goodsig && have_any_sigs);
1959 if (needpass == -1) {
1960 state_attach_puts (_("[-- Error: could not find beginning"
1961 " of PGP message! --]\n\n"), s);
1968 * Implementation of `encrypted_handler'.
1971 /* MIME handler for pgp/mime encrypted messages. */
1972 int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
1974 char tempfile[_POSIX_PATH_MAX];
1977 BODY *orig_body = a;
1982 if (!a || a->type != TYPEAPPLICATION || !a->subtype
1983 || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1984 || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1985 || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1986 if (s->flags & M_DISPLAY)
1987 state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1992 /* Move forward to the application/pgp-encrypted body. */
1995 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1997 if (s->flags & M_DISPLAY)
1998 state_attach_puts (_("[-- Error: could not create temporary file! "
2003 tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2005 tattach->goodsig = is_signed > 0;
2007 if (s->flags & M_DISPLAY)
2008 state_attach_puts (is_signed ?
2010 ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2011 _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
2014 FILE *savefp = s->fpin;
2017 rc = mutt_body_handler (tattach, s);
2022 * if a multipart/signed is the _only_ sub-part of a
2023 * multipart/encrypted, cache signature verification
2026 if (mutt_is_multipart_signed (tattach) && !tattach->next)
2027 orig_body->goodsig |= tattach->goodsig;
2029 if (s->flags & M_DISPLAY) {
2030 state_puts ("\n", s);
2031 state_attach_puts (is_signed ?
2033 ("[-- End of PGP/MIME signed and encrypted data --]\n")
2034 : _("[-- End of PGP/MIME encrypted data --]\n"), s);
2037 body_list_wipe(&tattach);
2041 mutt_unlink (tempfile);
2045 /* Support for application/smime */
2046 int smime_gpgme_application_handler (BODY * a, STATE * s)
2048 char tempfile[_POSIX_PATH_MAX];
2055 fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2057 if (s->flags & M_DISPLAY)
2058 state_attach_puts (_("[-- Error: could not create temporary file! "
2063 tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2065 tattach->goodsig = is_signed > 0;
2067 if (s->flags & M_DISPLAY)
2068 state_attach_puts (is_signed ?
2069 _("[-- The following data is S/MIME signed --]\n\n") :
2070 _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2073 FILE *savefp = s->fpin;
2076 rc = mutt_body_handler (tattach, s);
2081 * if a multipart/signed is the _only_ sub-part of a
2082 * multipart/encrypted, cache signature verification
2085 if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2086 if (!(a->goodsig = tattach->goodsig))
2087 a->warnsig = tattach->warnsig;
2089 else if (tattach->goodsig) {
2091 a->warnsig = tattach->warnsig;
2094 if (s->flags & M_DISPLAY) {
2095 state_puts ("\n", s);
2096 state_attach_puts (is_signed ?
2097 _("[-- End of S/MIME signed data --]\n") :
2098 _("[-- End of S/MIME encrypted data --]\n"), s);
2101 body_list_wipe(&tattach);
2105 mutt_unlink (tempfile);
2111 * Format an entry on the CRYPT key selection menu.
2114 * %k key id %K key id of the principal key
2116 * %a algorithm %A algorithm of the princ. key
2117 * %l length %L length of the princ. key
2118 * %f flags %F flags of the princ. key
2119 * %c capabilities %C capabilities of the princ. key
2120 * %t trust/validity of the key-uid association
2122 * %[...] date of key using strftime(3)
2126 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2127 const char *src, const char *prefix,
2128 const char *ifstr, const char *elstr,
2129 anytype data, format_flag flags)
2132 crypt_entry_t *entry;
2135 int optional = (flags & M_FORMAT_OPTIONAL);
2136 const char *s = NULL;
2142 /* if (isupper ((unsigned char) op)) */
2145 kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2148 switch (ascii_tolower (op)) {
2152 char buf2[STRING], *p;
2168 while (len > 0 && *cp != ']') {
2177 break; /* not enough space */
2187 if (do_locales && Locale)
2188 setlocale (LC_TIME, Locale);
2193 if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2194 tt = key->kobj->subkeys->timestamp;
2196 tm = localtime (&tt);
2198 strftime (buf2, sizeof (buf2), dest, tm);
2201 setlocale (LC_TIME, "C");
2203 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2204 snprintf (dest, destlen, fmt, buf2);
2211 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2212 snprintf (dest, destlen, fmt, entry->num);
2217 /* fixme: we need a way to distinguish between main and subkeys.
2218 Store the idx in entry? */
2219 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2220 snprintf (dest, destlen, fmt, crypt_keyid (key));
2225 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2226 snprintf (dest, destlen, fmt, key->uid);
2231 snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2232 if (key->kobj->subkeys)
2233 s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2236 snprintf (dest, destlen, fmt, s);
2241 snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2242 if (key->kobj->subkeys)
2243 val = key->kobj->subkeys->length;
2246 snprintf (dest, destlen, fmt, val);
2251 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2252 snprintf (dest, destlen, fmt, crypt_flags (kflags));
2254 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2259 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2260 snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2262 else if (!(kflags & (KEYFLAG_ABILITIES)))
2266 if ((kflags & KEYFLAG_ISX509))
2269 gpgme_user_id_t uid = NULL;
2272 for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2273 i++, uid = uid->next);
2275 switch (uid->validity) {
2276 case GPGME_VALIDITY_UNDEFINED:
2279 case GPGME_VALIDITY_NEVER:
2282 case GPGME_VALIDITY_MARGINAL:
2285 case GPGME_VALIDITY_FULL:
2288 case GPGME_VALIDITY_ULTIMATE:
2291 case GPGME_VALIDITY_UNKNOWN:
2297 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2298 snprintf (dest, destlen, fmt, s ? *s : 'B');
2301 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2302 snprintf (dest, destlen, fmt,
2303 gpgme_get_protocol_name (key->kobj->protocol));
2310 if (flags & M_FORMAT_OPTIONAL)
2311 m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2312 mutt_attach_fmt, data, 0);
2316 /* Used by the display fucntion to format a line. */
2317 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2319 crypt_key_t **key_table = (crypt_key_t **) menu->data;
2320 crypt_entry_t entry;
2322 entry.key = key_table[num];
2323 entry.num = num + 1;
2325 m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2326 option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2329 /* Compare two addresses and the keyid to be used for sorting. */
2330 static int _crypt_compare_address (const void *a, const void *b)
2332 crypt_key_t **s = (crypt_key_t **) a;
2333 crypt_key_t **t = (crypt_key_t **) b;
2336 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2339 return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2342 static int crypt_compare_address (const void *a, const void *b)
2344 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2345 : _crypt_compare_address (a, b));
2349 /* Compare two key IDs and the addresses to be used for sorting. */
2350 static int _crypt_compare_keyid (const void *a, const void *b)
2352 crypt_key_t **s = (crypt_key_t **) a;
2353 crypt_key_t **t = (crypt_key_t **) b;
2356 if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2359 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2362 static int crypt_compare_keyid (const void *a, const void *b)
2364 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2365 : _crypt_compare_keyid (a, b));
2368 /* Compare 2 creation dates and the addresses. For sorting. */
2369 static int _crypt_compare_date (const void *a, const void *b)
2371 crypt_key_t **s = (crypt_key_t **) a;
2372 crypt_key_t **t = (crypt_key_t **) b;
2373 unsigned long ts = 0, tt = 0;
2375 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2376 ts = (*s)->kobj->subkeys->timestamp;
2377 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2378 tt = (*t)->kobj->subkeys->timestamp;
2385 return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2388 static int crypt_compare_date (const void *a, const void *b)
2390 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2391 : _crypt_compare_date (a, b));
2394 /* Compare two trust values, the key length, the creation dates. the
2395 addresses and the key IDs. For sorting. */
2396 static int _crypt_compare_trust (const void *a, const void *b)
2398 crypt_key_t **s = (crypt_key_t **) a;
2399 crypt_key_t **t = (crypt_key_t **) b;
2400 unsigned long ts = 0, tt = 0;
2403 if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2404 - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2407 if ((*s)->kobj->uids)
2408 ts = (*s)->kobj->uids->validity;
2409 if ((*t)->kobj->uids)
2410 tt = (*t)->kobj->uids->validity;
2411 if ((r = (tt - ts)))
2414 if ((*s)->kobj->subkeys)
2415 ts = (*s)->kobj->subkeys->length;
2416 if ((*t)->kobj->subkeys)
2417 tt = (*t)->kobj->subkeys->length;
2421 if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2422 ts = (*s)->kobj->subkeys->timestamp;
2423 if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2424 tt = (*t)->kobj->subkeys->timestamp;
2430 if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2432 return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2435 static int crypt_compare_trust (const void *a, const void *b)
2437 return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2438 : _crypt_compare_trust (a, b));
2441 /* Print the X.500 Distinguished Name part KEY from the array of parts
2443 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2447 for (; dn->key; dn++) {
2448 if (!m_strcmp(dn->key, key)) {
2451 print_utf8 (fp, dn->value, m_strlen(dn->value));
2458 /* Print all parts of a DN in a standard sequence. */
2459 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2461 const char *stdpart[] = {
2462 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2464 int any = 0, any2 = 0, i;
2466 for (i = 0; stdpart[i]; i++) {
2469 any = print_dn_part (fp, dn, stdpart[i]);
2471 /* now print the rest without any specific ordering */
2472 for (; dn->key; dn++) {
2473 for (i = 0; stdpart[i]; i++) {
2474 if (!m_strcmp(dn->key, stdpart[i]))
2482 any = print_dn_part (fp, dn, dn->key);
2491 /* Parse an RDN; this is a helper to parse_dn(). */
2492 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2493 const unsigned char *string)
2495 const unsigned char *s, *s1;
2499 /* parse attributeType */
2500 for (s = string + 1; *s && *s != '='; s++);
2502 return NULL; /* error */
2505 return NULL; /* empty key */
2506 array->key = p_dupstr(string, n );
2507 p = (unsigned char *) array->key;
2510 if (*string == '#') { /* hexstring */
2512 for (s = string; hexdigitp (s); s++)
2516 return NULL; /* empty or odd number of digits */
2518 p = p_new(unsigned char, n + 1);
2519 array->value = (char *) p;
2520 for (s1 = string; n; s1 += 2, n--)
2524 else { /* regular v3 quoted string */
2525 for (n = 0, s = string; *s; s++) {
2526 if (*s == '\\') { /* pair */
2528 if (*s == ',' || *s == '=' || *s == '+'
2529 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2530 || *s == '\\' || *s == '\"' || *s == ' ')
2532 else if (hexdigitp (s) && hexdigitp (s + 1)) {
2537 return NULL; /* invalid escape sequence */
2539 else if (*s == '\"')
2540 return NULL; /* invalid encoding */
2541 else if (*s == ',' || *s == '=' || *s == '+'
2542 || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2548 p = p_new(unsigned char, n + 1);
2549 array->value = (char *) p;
2550 for (s = string; n; s++, n--) {
2553 if (hexdigitp (s)) {
2569 /* Parse a DN and return an array-ized one. This is not a validating
2570 parser and it does not support any old-stylish syntax; gpgme is
2571 expected to return only rfc2253 compatible strings. */
2572 static struct dn_array_s *parse_dn (const unsigned char *string)
2574 struct dn_array_s *array;
2575 ssize_t arrayidx, arraysize;
2578 arraysize = 7; /* C,ST,L,O,OU,CN,email */
2579 array = p_new(struct dn_array_s, arraysize + 1);
2582 while (*string == ' ')
2586 if (arrayidx >= arraysize) { /* mutt lacks a real safe_realoc - so we need to copy */
2587 struct dn_array_s *a2;
2590 a2 = p_new(struct dn_array_s, arraysize + 1);
2591 for (i = 0; i < arrayidx; i++) {
2592 a2[i].key = array[i].key;
2593 a2[i].value = array[i].value;
2598 array[arrayidx].key = NULL;
2599 array[arrayidx].value = NULL;
2600 string = parse_dn_part (array + arrayidx, string);
2604 while (*string == ' ')
2606 if (*string && *string != ',' && *string != ';' && *string != '+')
2607 goto failure; /* invalid delimiter */
2611 array[arrayidx].key = NULL;
2612 array[arrayidx].value = NULL;
2616 for (i = 0; i < arrayidx; i++) {
2617 p_delete(&array[i].key);
2618 p_delete(&array[i].value);
2625 /* Print a nice representation of the USERID and make sure it is
2626 displayed in a proper way, which does mean to reorder some parts
2627 for S/MIME's DNs. USERID is a string as returned by the gpgme key
2628 functions. It is utf-8 encoded. */
2629 static void parse_and_print_user_id (FILE * fp, const char *userid)
2634 if (*userid == '<') {
2635 s = strchr (userid + 1, '>');
2637 print_utf8 (fp, userid + 1, s - userid - 1);
2639 else if (*userid == '(')
2640 fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2641 else if (!digit_or_letter ((const unsigned char *) userid))
2642 fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2644 struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2647 fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2649 print_dn_parts (fp, dn);
2650 for (i = 0; dn[i].key; i++) {
2651 p_delete(&dn[i].key);
2652 p_delete(&dn[i].value);
2660 KEY_CAP_CAN_ENCRYPT,
2665 static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
2667 gpgme_subkey_t subkey = NULL;
2668 unsigned int ret = 0;
2671 case KEY_CAP_CAN_ENCRYPT:
2672 if (!(ret = key->can_encrypt))
2673 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2674 if ((ret = subkey->can_encrypt))
2677 case KEY_CAP_CAN_SIGN:
2678 if (!(ret = key->can_sign))
2679 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2680 if ((ret = subkey->can_sign))
2683 case KEY_CAP_CAN_CERTIFY:
2684 if (!(ret = key->can_certify))
2685 for (subkey = key->subkeys; subkey; subkey = subkey->next)
2686 if ((ret = subkey->can_certify))
2695 /* Print verbose information about a key or certificate to FP. */
2696 static void print_key_info (gpgme_key_t key, FILE * fp)
2699 const char *s = NULL, *s2 = NULL;
2702 char shortbuf[STRING];
2703 unsigned long aval = 0;
2707 gpgme_user_id_t uid = NULL;
2710 setlocale (LC_TIME, Locale);
2712 is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2714 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2719 fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2722 fputs (_("[Invalid]"), fp);
2726 print_utf8 (fp, s, m_strlen(s));
2728 parse_and_print_user_id (fp, s);
2732 if (key->subkeys && (key->subkeys->timestamp > 0)) {
2733 tt = key->subkeys->timestamp;
2735 tm = localtime (&tt);
2736 #ifdef HAVE_LANGINFO_D_T_FMT
2737 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2739 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2741 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2744 if (key->subkeys && (key->subkeys->expires > 0)) {
2745 tt = key->subkeys->expires;
2747 tm = localtime (&tt);
2748 #ifdef HAVE_LANGINFO_D_T_FMT
2749 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2751 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2753 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2757 s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2761 s2 = is_pgp ? "PGP" : "X.509";
2764 aval = key->subkeys->length;
2766 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2768 fprintf (fp, _("Key Usage .: "));
2771 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2772 fprintf (fp, "%s%s", delim, _("encryption"));
2775 if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2776 fprintf (fp, "%s%s", delim, _("signing"));
2779 if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2780 fprintf (fp, "%s%s", delim, _("certification"));
2786 s = key->subkeys->fpr;
2787 fputs (_("Fingerprint: "), fp);
2788 if (is_pgp && m_strlen(s) == 40) {
2789 for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2794 putc (is_pgp ? ' ' : ':', fp);
2795 if (is_pgp && i == 4)
2800 for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2803 putc (is_pgp ? ' ' : ':', fp);
2804 if (is_pgp && i == 7)
2808 fprintf (fp, "%s\n", s);
2811 if (key->issuer_serial) {
2812 s = key->issuer_serial;
2814 fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2817 if (key->issuer_name) {
2818 s = key->issuer_name;
2820 fprintf (fp, _("Issued By .: "));
2821 parse_and_print_user_id (fp, s);
2826 /* For PGP we list all subkeys. */
2828 gpgme_subkey_t subkey = NULL;
2830 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2834 if (m_strlen(s) == 16)
2835 s += 8; /* display only the short keyID */
2836 fprintf (fp, _("Subkey ....: 0x%s"), s);
2837 if (subkey->revoked) {
2839 fputs (_("[Revoked]"), fp);
2841 if (subkey->invalid) {
2843 fputs (_("[Invalid]"), fp);
2845 if (subkey->expired) {
2847 fputs (_("[Expired]"), fp);
2849 if (subkey->disabled) {
2851 fputs (_("[Disabled]"), fp);
2855 if (subkey->timestamp > 0) {
2856 tt = subkey->timestamp;
2858 tm = localtime (&tt);
2859 #ifdef HAVE_LANGINFO_D_T_FMT
2860 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2862 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2864 fprintf (fp, _("Valid From : %s\n"), shortbuf);
2867 if (subkey->expires > 0) {
2868 tt = subkey->expires;
2870 tm = localtime (&tt);
2871 #ifdef HAVE_LANGINFO_D_T_FMT
2872 strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2874 strftime (shortbuf, sizeof shortbuf, "%c", tm);
2876 fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2880 s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2885 aval = subkey->length;
2889 fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2891 fprintf (fp, _("Key Usage .: "));
2894 if (subkey->can_encrypt) {
2895 fprintf (fp, "%s%s", delim, _("encryption"));
2898 if (subkey->can_sign) {
2899 fprintf (fp, "%s%s", delim, _("signing"));
2902 if (subkey->can_certify) {
2903 fprintf (fp, "%s%s", delim, _("certification"));
2911 setlocale (LC_TIME, "C");
2915 /* Show detailed information about the selected key */
2916 static void verify_key (crypt_key_t * key)
2919 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2921 gpgme_ctx_t listctx = NULL;
2923 gpgme_key_t k = NULL;
2926 fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2928 mutt_perror (_("Can't create temporary file"));
2931 mutt_message _("Collecting data...");
2933 print_key_info (key->kobj, fp);
2935 err = gpgme_new (&listctx);
2937 fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2938 gpgme_strerror (err));
2941 if ((key->flags & KEYFLAG_ISX509))
2942 gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2946 while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2948 err = gpgme_op_keylist_start (listctx, s, 0);
2949 gpgme_key_release (k);
2952 err = gpgme_op_keylist_next (listctx, &k);
2954 fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2957 gpgme_op_keylist_end (listctx);
2959 print_key_info (k, fp);
2962 fputs (_("Error: certification chain to long - stopping here\n"), fp);
2968 gpgme_key_release (k);
2969 gpgme_release (listctx);
2971 mutt_clear_error ();
2972 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2973 mutt_do_pager (cmd, tempfile, 0, NULL);
2977 * Implementation of `findkeys'.
2981 /* Convert string_list_t into a pattern string suitable to be passed to GPGME.
2982 We need to convert spaces in an item into a '+' and '%' into
2984 static char *list_to_pattern (string_list_t * list)
2992 for (l = list; l; l = l->next) {
2993 for (s = l->data; *s; s++) {
2998 n++; /* delimiter or end of string */
3000 n++; /* make sure to allocate at least one byte */
3001 pattern = p = p_new(char, n);
3002 for (l = list; l; l = l->next) {
3007 for (s = l->data; *s; s++) {
3013 else if (*s == '+') {
3029 /* Return a list of keys which are candidates for the selection.
3030 Select by looking at the HINTS list. */
3031 static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
3034 crypt_key_t *db, *k, **kend;
3040 gpgme_user_id_t uid = NULL;
3042 pattern = list_to_pattern (hints);
3046 err = gpgme_new (&ctx);
3048 mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3056 if ((app & APPLICATION_PGP)) {
3057 /* Its all a mess. That old GPGME expects different things
3058 depending on the protocol. For gpg we don' t need percent
3059 escaped pappert but simple strings passed in an array to the
3060 keylist_ext_start function. */
3065 for (l = hints, n = 0; l; l = l->next) {
3066 if (l->data && *l->data)
3072 patarr = p_new(char *, n + 1);
3073 for (l = hints, n = 0; l; l = l->next) {
3074 if (l->data && *l->data)
3075 patarr[n++] = m_strdup(l->data);
3078 err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
3079 for (n = 0; patarr[n]; n++)
3080 p_delete(&patarr[n]);
3083 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3084 gpgme_release (ctx);
3089 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3090 unsigned int flags = 0;
3092 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3093 flags |= KEYFLAG_CANENCRYPT;
3094 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3095 flags |= KEYFLAG_CANSIGN;
3097 #if 0 /* DISABLED code */
3099 /* Bug in gpg. Capabilities are not listed for secret
3100 keys. Try to deduce them from the algorithm. */
3102 switch (key->subkeys[0].pubkey_algo) {
3104 flags |= KEYFLAG_CANENCRYPT;
3105 flags |= KEYFLAG_CANSIGN;
3107 case GPGME_PK_ELG_E:
3108 flags |= KEYFLAG_CANENCRYPT;
3111 flags |= KEYFLAG_CANSIGN;
3115 #endif /* DISABLED code */
3117 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3118 k = p_new(crypt_key_t, 1);
3127 if (gpg_err_code (err) != GPG_ERR_EOF)
3128 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3129 gpgme_op_keylist_end (ctx);
3134 if ((app & APPLICATION_SMIME)) {
3135 /* and now look for x509 certificates */
3136 gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3137 err = gpgme_op_keylist_start (ctx, pattern, 0);
3139 mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
3140 gpgme_release (ctx);
3145 while (!(err = gpgme_op_keylist_next (ctx, &key))) {
3146 unsigned int flags = KEYFLAG_ISX509;
3148 if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3149 flags |= KEYFLAG_CANENCRYPT;
3150 if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3151 flags |= KEYFLAG_CANSIGN;
3153 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3154 k = p_new(crypt_key_t, 1);
3163 if (gpg_err_code (err) != GPG_ERR_EOF)
3164 mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3165 gpgme_op_keylist_end (ctx);
3168 gpgme_release (ctx);
3173 /* Add the string STR to the list HINTS. This list is later used to
3175 static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
3180 if ((scratch = m_strdup(str)) == NULL)
3183 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3184 t = strtok (NULL, " ,.:\"()<>\n")) {
3185 if (m_strlen(t) > 3)
3186 hints = mutt_add_list(hints, t);
3193 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3194 will be set to true on return if the user did override the the
3196 static crypt_key_t *crypt_select_key (crypt_key_t * keys,
3197 address_t * p, const char *s,
3198 unsigned int app, int *forced_valid)
3201 crypt_key_t **key_table;
3204 char helpstr[STRING], buf[LONG_STRING];
3206 int (*f) (const void *, const void *);
3207 int menu_to_use = 0;
3212 /* build the key table */
3215 for (k = keys; k; k = k->next) {
3216 if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3223 p_realloc(&key_table, keymax);
3229 if (!i && unusable) {
3230 mutt_error _("All matching keys are marked expired/revoked.");
3236 switch (PgpSortKeys & SORT_MASK) {
3238 f = crypt_compare_date;
3241 f = crypt_compare_keyid;
3244 f = crypt_compare_address;
3248 f = crypt_compare_trust;
3251 qsort (key_table, i, sizeof (crypt_key_t *), f);
3253 if (app & APPLICATION_PGP)
3254 menu_to_use = MENU_KEY_SELECT_PGP;
3255 else if (app & APPLICATION_SMIME)
3256 menu_to_use = MENU_KEY_SELECT_SMIME;
3259 mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
3260 m_strcat(helpstr, sizeof(helpstr), buf);
3261 mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
3262 OP_GENERIC_SELECT_ENTRY);
3263 m_strcat(helpstr, sizeof(helpstr), buf);
3264 mutt_make_help (buf, sizeof (buf), _("Check key "),
3265 menu_to_use, OP_VERIFY_KEY);
3266 m_strcat(helpstr, sizeof(helpstr), buf);
3267 mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3268 m_strcat(helpstr, sizeof(helpstr), buf);
3270 menu = mutt_new_menu ();
3272 menu->make_entry = crypt_entry;
3273 menu->menu = menu_to_use;
3274 menu->help = helpstr;
3275 menu->data = key_table;
3280 if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3281 ts = _("PGP and S/MIME keys matching");
3282 else if ((app & APPLICATION_PGP))
3283 ts = _("PGP keys matching");
3284 else if ((app & APPLICATION_SMIME))
3285 ts = _("S/MIME keys matching");
3287 ts = _("keys matching");
3290 snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3292 snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3296 mutt_clear_error ();
3300 switch (mutt_menuLoop (menu)) {
3302 verify_key (key_table[menu->current]);
3303 menu->redraw = REDRAW_FULL;
3307 mutt_message ("%s", key_table[menu->current]->uid);
3310 case OP_GENERIC_SELECT_ENTRY:
3311 /* FIXME make error reporting more verbose - this should be
3312 easy because gpgme provides more information */
3313 if (option (OPTPGPCHECKTRUST)) {
3314 if (!crypt_key_is_valid (key_table[menu->current])) {
3315 mutt_error _("This key can't be used: "
3316 "expired/disabled/revoked.");
3321 if (option (OPTPGPCHECKTRUST) &&
3322 (!crypt_id_is_valid (key_table[menu->current])
3323 || !crypt_id_is_strong (key_table[menu->current]))) {
3325 char buff[LONG_STRING];
3327 if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3328 s = N_("ID is expired/disabled/revoked.");
3330 gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3331 gpgme_user_id_t uid = NULL;
3336 uid = key_table[menu->current]->kobj->uids;
3337 for (j = 0; (j < key_table[menu->current]->idx) && uid;
3338 j++, uid = uid->next);
3340 val = uid->validity;
3343 case GPGME_VALIDITY_UNKNOWN:
3344 case GPGME_VALIDITY_UNDEFINED:
3345 warn_s = N_("ID has undefined validity.");
3347 case GPGME_VALIDITY_NEVER:
3348 warn_s = N_("ID is not valid.");
3350 case GPGME_VALIDITY_MARGINAL:
3351 warn_s = N_("ID is only marginally valid.");
3353 case GPGME_VALIDITY_FULL:
3354 case GPGME_VALIDITY_ULTIMATE:
3358 snprintf (buff, sizeof (buff),
3359 _("%s Do you really want to use the key?"), _(warn_s));
3361 if (mutt_yesorno (buff, 0) != 1) {
3362 mutt_clear_error ();
3369 k = crypt_copy_key (key_table[menu->current]);
3380 mutt_menuDestroy (&menu);
3381 p_delete(&key_table);
3383 set_option (OPTNEEDREDRAW);
3388 static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
3389 unsigned int app, int *forced_valid)
3392 string_list_t *hints = NULL;
3397 int this_key_has_strong;
3398 int this_key_has_weak;
3399 int this_key_has_invalid;
3402 crypt_key_t *keys, *k;
3403 crypt_key_t *the_valid_key = NULL;
3404 crypt_key_t *matches = NULL;
3405 crypt_key_t **matches_endp = &matches;
3409 if (a && a->mailbox)
3410 hints = crypt_add_string_to_hints (hints, a->mailbox);
3411 if (a && a->personal)
3412 hints = crypt_add_string_to_hints (hints, a->personal);
3414 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3415 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3417 string_list_wipe(&hints);
3422 for (k = keys; k; k = k->next) {
3423 if (abilities && !(k->flags & abilities)) {
3427 this_key_has_weak = 0; /* weak but valid match */
3428 this_key_has_invalid = 0; /* invalid match */
3429 this_key_has_strong = 0; /* strong and valid match */
3430 match = 0; /* any match */
3432 r = rfc822_parse_adrlist (NULL, k->uid);
3433 for (p = r; p; p = p->next) {
3434 int validity = crypt_id_matches_addr (a, p, k);
3436 if (validity & CRYPT_KV_MATCH) /* something matches */
3439 /* is this key a strong candidate? */
3440 if ((validity & CRYPT_KV_VALID)
3441 && (validity & CRYPT_KV_STRONGID)
3442 && (validity & CRYPT_KV_ADDR)) {
3443 if (the_valid_key && the_valid_key != k)
3446 this_key_has_strong = 1;
3448 else if ((validity & CRYPT_KV_MATCH)
3449 && !(validity & CRYPT_KV_VALID))
3450 this_key_has_invalid = 1;
3451 else if ((validity & CRYPT_KV_MATCH)
3452 && (!(validity & CRYPT_KV_STRONGID)
3453 || !(validity & CRYPT_KV_ADDR)))
3454 this_key_has_weak = 1;
3456 address_list_wipe(&r);
3461 if (!this_key_has_strong && this_key_has_invalid)
3463 if (!this_key_has_strong && this_key_has_weak)
3466 *matches_endp = tmp = crypt_copy_key (k);
3467 matches_endp = &tmp->next;
3468 the_valid_key = tmp;
3472 crypt_free_key (&keys);
3475 if (the_valid_key && !multi && !weak
3476 && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3478 * There was precisely one strong match on a valid ID, there
3479 * were no valid keys with weak matches, and we aren't
3480 * interested in seeing invalid keys.
3482 * Proceed without asking the user.
3484 k = crypt_copy_key (the_valid_key);
3488 * Else: Ask the user.
3490 k = crypt_select_key (matches, a, NULL, app, forced_valid);
3492 crypt_free_key (&matches);
3501 static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
3502 unsigned int app, int *forced_valid)
3504 string_list_t *hints = NULL;
3506 crypt_key_t *matches = NULL;
3507 crypt_key_t **matches_endp = &matches;
3511 mutt_message (_("Looking for keys matching \"%s\"..."), p);
3515 hints = crypt_add_string_to_hints (hints, p);
3516 keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
3517 string_list_wipe(&hints);
3522 for (k = keys; k; k = k->next) {
3523 if (abilities && !(k->flags & abilities))
3528 if (!*p || !m_strcasecmp(p, crypt_keyid (k))
3529 || (!m_strncasecmp(p, "0x", 2)
3530 && !m_strcasecmp(p + 2, crypt_keyid (k)))
3531 || (option (OPTPGPLONGIDS)
3532 && !m_strncasecmp(p, "0x", 2)
3533 && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
3534 || m_stristr(k->uid, p)) {
3537 *matches_endp = tmp = crypt_copy_key (k);
3538 matches_endp = &tmp->next;
3542 crypt_free_key (&keys);
3545 k = crypt_select_key (matches, NULL, p, app, forced_valid);
3546 crypt_free_key (&matches);
3553 /* Display TAG as a prompt to ask for a key. If WHATFOR is not null
3554 use it as default and store it under that label as the next
3555 default. ABILITIES describe the required key abilities (sign,
3556 encrypt) and APP the type of the requested key; ether S/MIME or
3557 PGP. Return a copy of the key or NULL if not found. */
3558 static crypt_key_t *crypt_ask_for_key (char *tag,
3561 unsigned int app, int *forced_valid)
3565 struct crypt_cache *l = NULL;
3569 forced_valid = &dummy;
3571 mutt_clear_error ();
3577 for (l = id_defaults; l; l = l->next)
3578 if (!m_strcasecmp(whatfor, l->what)) {
3579 m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
3587 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
3592 m_strreplace(&l->dflt, resp);
3594 l = p_new(struct crypt_cache, 1);
3595 l->next = id_defaults;
3597 l->what = m_strdup(whatfor);
3598 l->dflt = m_strdup(resp);
3602 if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
3610 /* This routine attempts to find the keyids of the recipients of a
3611 message. It returns NULL if any of the keys can not be found. */
3612 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
3615 char *keylist = NULL, *t;
3617 ssize_t keylist_size = 0;
3618 ssize_t keylist_used = 0;
3619 address_t *tmp = NULL, *addr = NULL;
3620 address_t **last = &tmp;
3623 crypt_key_t *k_info, *key;
3624 const char *fqdn = mutt_fqdn (1);
3627 *r_application = APPLICATION_PGP | APPLICATION_SMIME;
3630 for (i = 0; i < 3; i++) {
3645 *last = address_list_dup (p);
3647 last = &((*last)->next);
3650 rfc822_qualify(tmp, fqdn);
3651 address_list_uniq(tmp);
3653 for (p = tmp; p; p = p->next) {
3654 char buf[LONG_STRING];
3655 int forced_valid = 0;
3660 if ((keyID = mutt_crypt_hook (p)) != NULL) {
3663 snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
3665 if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
3666 /* check for e-mail address */
3667 if ((t = strchr (keyID, '@')) &&
3668 (addr = rfc822_parse_adrlist (NULL, keyID))) {
3669 rfc822_qualify(addr, fqdn);
3673 k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
3674 app, &forced_valid);
3679 address_list_wipe(&tmp);
3680 address_list_wipe(&addr);
3686 && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
3687 app, &forced_valid)) == NULL) {
3688 snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
3690 if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
3692 &forced_valid)) == NULL) {
3694 address_list_wipe(&tmp);
3695 address_list_wipe(&addr);
3703 const char *s = crypt_fpr (key);
3705 keylist_size += m_strlen(s) + 4 + 1;
3706 p_realloc(&keylist, keylist_size);
3707 sprintf (keylist + keylist_used, "%s0x%s%s",
3708 keylist_used ? " " : "", s, forced_valid ? "!" : "");
3710 keylist_used = m_strlen(keylist);
3712 crypt_free_key (&key);
3713 address_list_wipe(&addr);
3715 address_list_wipe(&tmp);
3719 char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3721 return find_keys (to, cc, bcc, APPLICATION_PGP);
3724 char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
3726 return find_keys (to, cc, bcc, APPLICATION_SMIME);
3730 * Implementation of `init'.
3733 /* Initialization. */
3734 static void init_gpgme (void)
3736 /* Make sure that gpg-agent is running. */
3737 if (!getenv ("GPG_AGENT_INFO")) {
3738 mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
3739 if (mutt_any_key_to_continue (NULL) == -1)
3744 void pgp_gpgme_init (void)
3749 void smime_gpgme_init (void)
3753 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
3756 char input_signas[STRING];
3759 if (msg->security & APPLICATION_PGP)
3761 else if (msg->security & APPLICATION_SMIME)
3766 mutt_multi_choice (_
3767 ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3771 mutt_multi_choice (_
3772 ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3776 case 1: /* (e)ncrypt */
3777 msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3778 msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3781 case 2: /* (s)ign */
3782 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3783 msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3786 case 3: /* sign (a)s */
3787 /* unset_option(OPTCRYPTCHECKTRUST); */
3788 if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3789 is_smime ? APPLICATION_SMIME :
3790 APPLICATION_PGP, NULL))) {
3791 snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
3792 m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
3794 crypt_free_key (&p);
3796 msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3798 *redraw = REDRAW_FULL;
3801 case 4: /* (b)oth */
3803 (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
3806 case 5: /* (p)gp or s/(m)ime */
3807 is_smime = !is_smime;
3810 case 6: /* (c)lear */
3815 if (choice == 6 || choice == 7);
3816 else if (is_smime) {
3817 msg->security &= ~APPLICATION_PGP;
3818 msg->security |= APPLICATION_SMIME;
3821 msg->security &= ~APPLICATION_SMIME;
3822 msg->security |= APPLICATION_PGP;
3825 return (msg->security);
3828 int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
3830 return gpgme_send_menu (msg, redraw, 0);
3833 int smime_gpgme_send_menu (HEADER * msg, int *redraw)
3835 return gpgme_send_menu (msg, redraw, 1);
3838 static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
3840 address_t *sender = NULL;
3841 unsigned int ret = 1;
3844 h->env->from = mutt_expand_aliases (h->env->from);
3845 sender = h->env->from;
3847 else if (h->env->sender) {
3848 h->env->sender = mutt_expand_aliases (h->env->sender);
3849 sender = h->env->sender;
3853 if (signature_key) {
3854 gpgme_key_t key = signature_key;
3855 gpgme_user_id_t uid = NULL;
3856 int sender_length = 0;
3859 sender_length = m_strlen(sender->mailbox);
3860 for (uid = key->uids; uid && ret; uid = uid->next) {
3861 uid_length = m_strlen(uid->email);
3862 if (1 && (uid->email[0] == '<')
3863 && (uid->email[uid_length - 1] == '>')
3864 && (uid_length == sender_length + 2)
3865 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3870 mutt_any_key_to_continue ("Failed to verify sender");
3873 mutt_any_key_to_continue ("Failed to figure out sender");
3875 if (signature_key) {
3876 gpgme_key_release (signature_key);
3877 signature_key = NULL;
3883 int smime_gpgme_verify_sender (HEADER * h)
3885 return verify_sender (h, GPGME_PROTOCOL_CMS);
3888 void pgp_gpgme_invoke_import(const char *fname)
3890 gpgme_ctx_t ctx = create_gpgme_context(0);
3894 err = gpgme_data_new_from_file(&data, fname, 1);
3896 mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3901 err = gpgme_op_import(ctx, data);
3903 mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3904 gpgme_data_release(data);
3909 gpgme_data_release(data);
3914 static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
3918 char tempfname[_POSIX_PATH_MAX];
3920 tempfp = m_tempfile(tempfname, sizeof(tempfname), NONULL(MCore.tmpdir), NULL);
3921 if (tempfp == NULL) {
3922 mutt_perror (_("Can't create temporary file"));
3931 mutt_body_handler (top, &s);
3934 pgp_gpgme_invoke_import(tempfname);
3935 mutt_unlink (tempfname);
3938 void pgp_gpgme_from_attachment_list (FILE * fp, int tag, BODY * top)
3941 set_option (OPTDONTHANDLEPGPKEYS);
3943 for (; top; top = top->next) {
3944 if (!tag || top->tagged)
3945 pgp_extract_keys_from_attachment (fp, top);
3951 unset_option (OPTDONTHANDLEPGPKEYS);