* Copyright (C) 2001 Thomas Roessler <roessler@guug.de>
* Oliver Ehli <elmy@acm.org>
* Copyright (C) 2002, 2003, 2004 g10 Code GmbH
- *
- * This file is part of mutt-ng, see http://www.muttng.org/.
- * It's licensed under the GNU General Public License,
- * please see the file GPL in the top level source directory.
+ */
+/*
+ * Copyright © 2006 Pierre Habouzit
*/
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef CRYPT_BACKEND_GPGME
+#include <lib-lib/lib-lib.h>
-#include <lib-lib/mem.h>
-#include <lib-lib/str.h>
-#include <lib-lib/ascii.h>
-#include <lib-lib/macros.h>
-#include <lib-lib/file.h>
+#include <gpgme.h>
#include <lib-mime/mime.h>
-
#include <lib-ui/curses.h>
#include <lib-ui/enter.h>
+#include <lib-ui/menu.h>
+
+#include "crypt.h"
-#include "mutt.h"
-#include <lib-crypt/crypt.h>
-#include "mutt_menu.h"
+#include "lib.h"
+#include "alias.h"
#include "handler.h"
#include "copy.h"
#include "pager.h"
#include "recvattach.h"
#include "sort.h"
-#include "lib/debug.h"
-
-#include <sys/wait.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <gpgme.h>
-
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-#ifdef HAVE_LANGINFO_D_T_FMT
-#include <langinfo.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif
-
-/*
- * Helper macros.
- */
-#define digitp(p) (*(p) >= '0' && *(p) <= '9')
-#define hexdigitp(a) (digitp (a) \
- || (*(a) >= 'A' && *(a) <= 'F') \
- || (*(a) >= 'a' && *(a) <= 'f'))
-#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
- *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
-#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
-
/* Values used for comparing addresses. */
#define CRYPT_KV_VALID 1
#define CRYPT_KV_ADDR 2
} crypt_key_t;
typedef struct crypt_entry {
- size_t num;
+ ssize_t num;
crypt_key_t *key;
} crypt_entry_t;
/* Print the utf-8 encoded string BUF of length LEN bytes to stream
FP. Convert the character set. */
-static void print_utf8 (FILE * fp, const char *buf, size_t len)
+static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
{
char *tstr;
tstr = p_dupstr(buf, len);
- mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
+ mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
fputs (tstr, fp);
p_delete(&tstr);
}
{
gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
gpgme_user_id_t uid = NULL;
- unsigned int is_strong = 0;
- unsigned int i = 0;
+ int is_strong = 0;
+ int i = 0;
if ((key->flags & KEYFLAG_ISX509))
return 1;
int err = 0;
gpgme_data_t data;
- mutt_mktemp (tempfile);
- fptmp = safe_fopen (tempfile, "w+");
+ fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!fptmp) {
- mutt_perror (tempfile);
+ mutt_perror (_("Can't create temporary file"));
return NULL;
}
buf[0] = c;
gpgme_data_write (data, buf, 1);
}
- fclose (fptmp);
gpgme_data_seek (data, 0, SEEK_SET);
- }
- else {
- fclose (fptmp);
+ } else {
err = gpgme_data_new_from_file (&data, tempfile, 1);
}
+ m_fclose(&fptmp);
unlink (tempfile);
if (err) {
mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
int err;
char tempfile[_POSIX_PATH_MAX];
FILE *fp;
- size_t nread = 0;
+ ssize_t nread = 0;
- mutt_mktemp (tempfile);
- fp = safe_fopen (tempfile, "w+");
+ fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!fp) {
- mutt_perror (tempfile);
+ mutt_perror (_("Can't create temporary file"));
return NULL;
}
while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
if (fwrite (buf, nread, 1, fp) != 1) {
- mutt_perror (tempfile);
- fclose (fp);
+ mutt_perror (_("Can't create temporary file"));
+ m_fclose(&fp);
unlink (tempfile);
return NULL;
}
if (ret_fp)
rewind (fp);
else
- fclose (fp);
+ m_fclose(&fp);
if (nread == -1) {
mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
unlink (tempfile);
- fclose (fp);
+ m_fclose(&fp);
return NULL;
}
if (ret_fp)
}
+/* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
+static gpgme_error_t
+gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
+ int secret)
+{
+ gpgme_ctx_t listctx;
+ gpgme_error_t err;
+
+ if (!ctx || !r_key || !fpr)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (strlen (fpr) < 8) /* We have at least a key ID. */
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* FIXME: We use our own context because we have to avoid the user's
+ I/O callback handlers. */
+ err = gpgme_new (&listctx);
+ if (err)
+ return err;
+ gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
+ err = gpgme_op_keylist_start (listctx, fpr, secret);
+ if (!err)
+ err = gpgme_op_keylist_next (listctx, r_key);
+ gpgme_release (listctx);
+ return err;
+}
+
/* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
The keys must be space delimited. */
static gpgme_key_t *create_recipient_set (const char *keylist,
do {
while (*s == ' ')
s++;
- for (i = 0; *s && *s != ' ' && i < sizeof (buf) - 1;)
+ for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
buf[i++] = *s++;
buf[i] = 0;
if (*buf) {
key. */
buf[i - 1] = 0;
- err = gpgme_get_key (context, buf, &key, 0);
+ err = gpgme_get_key2 (context, buf, &key, 0);
if (!err)
key->uids->validity = GPGME_VALIDITY_FULL;
buf[i - 1] = '!';
}
else
- err = gpgme_get_key (context, buf, &key, 0);
+ err = gpgme_get_key2 (context, buf, &key, 0);
if (!err) {
p_realloc(&rset, rset_n + 1);
which must have been allocated by the caller with size BUFLEN.
Returns 0 on success or -1 in case of an error. The return string
is truncted to BUFLEN - 1. */
-static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
+static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
{
gpgme_sign_result_t result = NULL;
const char *algorithm_name = NULL;
state_attach_puts (p, s);
}
-/*
- * Implementation of `sign_message'.
- */
+/* Implementation of `sign_message'. */
/* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
USE_SMIME is passed as true. Returns the new body or NULL on
return NULL;
}
- t = mutt_new_body ();
+ t = body_new();
t->type = TYPEMULTIPART;
t->subtype = m_strdup("signed");
t->encoding = ENC7BIT;
t->use_disp = 0;
t->disposition = DISPINLINE;
- mutt_generate_boundary (&t->parameter);
- mutt_set_parameter ("protocol",
- use_smime ? "application/pkcs7-signature"
- : "application/pgp-signature", &t->parameter);
+ parameter_set_boundary(&t->parameter);
+ parameter_setval(&t->parameter, "protocol",
+ use_smime ? "application/pkcs7-signature"
+ : "application/pgp-signature");
/* Get the micalg from gpgme. Old gpgme versions don't support this
for S/MIME so we assume sha-1 in this case. */
if (!get_micalg (ctx, buf, sizeof buf))
- mutt_set_parameter ("micalg", buf, &t->parameter);
+ parameter_setval(&t->parameter, "micalg", buf);
else if (use_smime)
- mutt_set_parameter ("micalg", "sha1", &t->parameter);
+ parameter_setval(&t->parameter, "micalg", "sha1");
gpgme_release (ctx);
t->parts = a;
a = t;
- t->parts->next = mutt_new_body ();
+ t->parts->next = body_new();
t = t->parts->next;
t->type = TYPEAPPLICATION;
if (use_smime) {
t->subtype = m_strdup("pkcs7-signature");
- mutt_set_parameter ("name", "smime.p7s", &t->parameter);
+ parameter_setval(&t->parameter, "name", "smime.p7s");
t->encoding = ENCBASE64;
t->use_disp = 1;
t->disposition = DISPATTACH;
}
-BODY *pgp_gpgme_sign_message (BODY * a)
+BODY *crypt_pgp_sign_message (BODY * a)
{
return sign_message (a, 0);
}
-BODY *smime_gpgme_sign_message (BODY * a)
+BODY *crypt_smime_sign_message (BODY * a)
{
return sign_message (a, 1);
}
/* Encrypt the mail body A to all keys given as space separated keyids
or fingerprints in KEYLIST and return the encrypted body. */
-BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
+BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
{
char *outfile = NULL;
BODY *t;
if (!outfile)
return NULL;
- t = mutt_new_body ();
+ t = body_new();
t->type = TYPEMULTIPART;
t->subtype = m_strdup("encrypted");
t->encoding = ENC7BIT;
t->use_disp = 0;
t->disposition = DISPINLINE;
- mutt_generate_boundary (&t->parameter);
- mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
+ parameter_set_boundary(&t->parameter);
+ parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
- t->parts = mutt_new_body ();
+ t->parts = body_new();
t->parts->type = TYPEAPPLICATION;
t->parts->subtype = m_strdup("pgp-encrypted");
t->parts->encoding = ENC7BIT;
- t->parts->next = mutt_new_body ();
+ t->parts->next = body_new();
t->parts->next->type = TYPEAPPLICATION;
t->parts->next->subtype = m_strdup("octet-stream");
t->parts->next->encoding = ENC7BIT;
/* Encrypt the mail body A to all keys given as space separated
fingerprints in KEYLIST and return the S/MIME encrypted body. */
-BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
+BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
{
char *outfile = NULL;
BODY *t;
if (!outfile)
return NULL;
- t = mutt_new_body ();
+ t = body_new();
t->type = TYPEAPPLICATION;
t->subtype = m_strdup("pkcs7-mime");
- mutt_set_parameter ("name", "smime.p7m", &t->parameter);
- mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
+ parameter_setval(&t->parameter, "name", "smime.p7m");
+ parameter_setval(&t->parameter, "smime-type", "enveloped-data");
t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
t->use_disp = 1;
t->disposition = DISPATTACH;
}
-/*
- * Implementation of `verify_one'.
- */
+/* Implementation of `verify_one'. */
/* Display the common attributes of the signature summary SUM.
Return 1 if there is is a severe warning.
if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
gpgme_verify_result_t result;
gpgme_signature_t sig;
- unsigned int i;
+ int i;
result = gpgme_op_verify_result (ctx);
const char *t0 = NULL, *t1 = NULL;
gpgme_verify_result_t result;
gpgme_signature_t sig;
- unsigned int i;
+ int i;
state_attach_puts (_("A system error occurred"), s);
int i, is_pgp;
char *buf, *p;
const char *prefix = _("Fingerprint: ");
+ ssize_t bufsize;
if (!key)
return;
return;
is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
- buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
- strcpy (buf, prefix); /* __STRCPY_CHECKED__ */
+ bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
+ buf = p_new(char, bufsize);
+ m_strcpy(buf, bufsize, prefix);
p = buf + m_strlen(buf);
if (is_pgp && m_strlen(s) == 40) { /* PGP v4 style formatted. */
for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
/* Show information about one signature. This fucntion is called with
the context CTX of a sucessful verification operation and the
enumerator IDX which should start at 0 and incremete for each
- call/signature.
+ call/signature.
Return values are: 0 for normal procession, 1 for a bad signature,
2 for a signature with a warning or -1 for no more signature. */
if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
anybad = 1;
- err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
+ err = gpgme_get_key2 (ctx, fpr, &key, 0); /* secret key? */
if (!err) {
uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
if (!signature_key)
/* Do the actual verification step. With IS_SMIME set to true we
assume S/MIME (surprise!) */
-static int verify_one (BODY * sigbdy, STATE * s,
- const char *tempfile, int is_smime)
+int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
{
int badsig = -1;
int anywarn = 0;
if (is_smime)
gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
- err = gpgme_data_new_from_file (&message, tempfile, 1);
+ err = gpgme_data_new_from_stream(&message, fp);
if (err) {
gpgme_data_release (signature);
mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
if (!badsig) {
gpgme_verify_result_t result;
gpgme_sig_notation_t notation;
- gpgme_signature_t signature;
+ gpgme_signature_t sig;
result = gpgme_op_verify_result (ctx);
if (result) {
- for (signature = result->signatures; signature;
- signature = signature->next) {
- if (signature->notations) {
+ for (sig = result->signatures; sig; sig = sig->next) {
+ if (sig->notations) {
state_attach_puts ("*** Begin Notation (signature by: ", s);
- state_attach_puts (signature->fpr, s);
+ state_attach_puts (sig->fpr, s);
state_attach_puts (") ***\n", s);
- for (notation = signature->notations; notation;
- notation = notation->next) {
+ for (notation = sig->notations; notation; notation = notation->next)
+ {
if (notation->name) {
state_attach_puts (notation->name, s);
state_attach_puts ("=", s);
gpgme_release (ctx);
state_attach_puts (_("[-- End signature information --]\n\n"), s);
- debug_print (1, ("returning %d.\n", badsig));
return badsig ? 1 : anywarn ? 2 : 0;
}
-int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
-{
- return verify_one (sigbdy, s, tempfile, 0);
-}
-
-int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
-{
- return verify_one (sigbdy, s, tempfile, 1);
-}
-
/*
* Implementation of `decrypt_part'.
*/
{
struct stat info;
BODY *tattach;
- int err;
+ int err = 0;
gpgme_ctx_t ctx;
gpgme_data_t ciphertext, plaintext;
int maybe_signed = 0;
/* Decrypt a PGP/MIME message in FPIN and B and return a new body and
the stream in CUR and FPOUT. Returns 0 on success. */
-int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
+int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
{
char tempfile[_POSIX_PATH_MAX];
STATE s;
p_clear(&s, 1);
s.fpin = fpin;
- mutt_mktemp (tempfile);
- if (!(*fpout = safe_fopen (tempfile, "w+"))) {
- mutt_perror (tempfile);
+ *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!*fpout) {
+ mutt_perror (_("Can't create temporary file"));
return -1;
}
unlink (tempfile);
/* Decrypt a S/MIME message in FPIN and B and return a new body and
the stream in CUR and FPOUT. Returns 0 on success. */
-int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
+int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
BODY ** cur)
{
char tempfile[_POSIX_PATH_MAX];
FILE *tmpfp = NULL;
int is_signed;
long saved_b_offset;
- size_t saved_b_length;
+ ssize_t saved_b_length;
int saved_b_type;
if (!mutt_is_application_smime (b))
p_clear(&s, 1);
s.fpin = fpin;
fseeko (s.fpin, b->offset, 0);
- mutt_mktemp (tempfile);
- if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
- mutt_perror (tempfile);
+ tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!tmpfp) {
+ mutt_perror (_("Can't create temporary file"));
return -1;
}
mutt_unlink (tempfile);
p_clear(&s, 1);
s.fpin = tmpfp;
s.fpout = 0;
- mutt_mktemp (tempfile);
- if (!(*fpout = safe_fopen (tempfile, "w+"))) {
- mutt_perror (tempfile);
+ *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!*fpout) {
+ mutt_perror (_("Can't create temporary file"));
return -1;
}
mutt_unlink (tempfile);
b->type = saved_b_type;
b->length = saved_b_length;
b->offset = saved_b_offset;
- fclose (tmpfp);
+ m_fclose(&tmpfp);
rewind (*fpout);
if (*cur && !is_signed && !(*cur)->parts
&& mutt_is_application_smime (*cur)) {
p_clear(&s, 1);
s.fpin = *fpout;
fseeko (s.fpin, bb->offset, 0);
- mutt_mktemp (tempfile);
- if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
- mutt_perror (tempfile);
+ tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!tmpfp) {
+ mutt_perror (_("Can't create temporary file"));
return -1;
}
mutt_unlink (tempfile);
bb->length = ftello (s.fpout);
bb->offset = 0;
rewind (tmpfp);
- fclose (*fpout);
+ m_fclose(&*fpout);
p_clear(&s, 1);
s.fpin = tmpfp;
s.fpout = 0;
- mutt_mktemp (tempfile);
- if (!(*fpout = safe_fopen (tempfile, "w+"))) {
- mutt_perror (tempfile);
+ *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!*fpout) {
+ mutt_perror (_("Can't create temporary file"));
return -1;
}
mutt_unlink (tempfile);
bb->type = saved_b_type;
bb->length = saved_b_length;
bb->offset = saved_b_offset;
- fclose (tmpfp);
+ m_fclose(&tmpfp);
rewind (*fpout);
- mutt_free_body (cur);
+ body_list_wipe(cur);
*cur = tmp_b;
}
return *cur ? 0 : -1;
}
-/*
+/*
* Implementation of `pgp_check_traditional'.
*/
char tempfile[_POSIX_PATH_MAX];
char buf[HUGE_STRING];
FILE *tfp;
+ int tempfd;
short sgn = 0;
short enc = 0;
if (tagged_only && !b->tagged)
return 0;
- mutt_mktemp (tempfile);
- if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
+ tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
unlink (tempfile);
return 0;
}
- if ((tfp = fopen (tempfile, "r")) == NULL) {
+ if ((tfp = fopen(tempfile, "r")) == NULL) {
unlink (tempfile);
return 0;
}
sgn = 1;
}
}
- safe_fclose (&tfp);
+ m_fclose(&tfp);
unlink (tempfile);
if (!enc && !sgn)
/* fix the content type */
- mutt_set_parameter ("format", "fixed", &b->parameter);
- mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed",
- &b->parameter);
-
+ parameter_setval(&b->parameter, "format", "fixed");
+ parameter_setval(&b->parameter, "x-action",
+ enc ? "pgp-encrypted" : "pgp-signed");
return 1;
}
-int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
+int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
{
int rv = 0;
int r;
for (; b; b = b->next) {
if (is_multipart (b))
- rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
+ rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
else if (b->type == TYPETEXT) {
if ((r = mutt_is_application_pgp (b)))
rv = (rv || r);
}
-/*
- * Implementation of `application_handler'.
- */
+/* Implementation of `application_handler'. */
-/*
+/*
Copy a clearsigned message, and strip the signature and PGP's
dash-escaping.
-
+
XXX - charset handling: We assume that it is safe to do
character set decoding first, dash decoding second here, while
we do it the other way around in the main handler.
-
+
(Note that we aren't worse than Outlook & Cie in this, and also
note that we can successfully handle anything produced by any
existing versions of mutt.) */
{
char buf[HUGE_STRING];
short complete, armor_header;
- FGETCONV *fc;
+ fgetconv_t *fc;
char *fname;
FILE *fp;
unlink (fname);
p_delete(&fname);
- fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
+ fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
for (complete = 1, armor_header = 1;
fgetconvs (buf, sizeof (buf), fc) != NULL;
}
fgetconv_close (&fc);
- fclose (fp);
+ m_fclose(&fp);
}
/* Support for classic_application/pgp */
-int pgp_gpgme_application_handler (BODY * m, STATE * s)
+int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
{
int needpass = -1, pgp_keyblock = 0;
int clearsign = 0;
char body_charset[STRING]; /* Only used for clearsigned messages. */
- debug_print (2, ("Entering pgp_application_pgp handler\n"));
-
/* For clearsigned messages we won't be able to get a character set
but we know that this may only be text thus we assume Latin-1
here. */
/*
* Now, copy cleartext to the screen. NOTE - we expect that PGP
- * outputs utf-8 cleartext. This may not always be true, but it
+ * outputs utf-8 cleartext. This may not always be true, but it
* seems to be a reasonable guess.
*/
copy_clearsigned (armored_data, s, body_charset);
}
else if (pgpout) {
- FGETCONV *fc;
+ fgetconv_t *fc;
int c;
rewind (pgpout);
- fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
+ fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
while ((c = fgetconv (fc)) != EOF) {
state_putc (c, s);
if (c == '\n' && s->prefix)
}
if (pgpout) {
- safe_fclose (&pgpout);
+ m_fclose(&pgpout);
}
}
else {
" of PGP message! --]\n\n"), s);
return (-1);
}
- debug_print (2, ("Leaving pgp_application_pgp handler\n"));
return (err);
}
-/*
- * Implementation of `encrypted_handler'.
- */
+/* Implementation of `encrypted_handler'. */
/* MIME handler for pgp/mime encrypted messages. */
-int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
+int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
{
char tempfile[_POSIX_PATH_MAX];
FILE *fpout;
int is_signed;
int rc = 0;
- debug_print (2, ("Entering pgp_encrypted handler\n"));
a = a->parts;
if (!a || a->type != TYPEAPPLICATION || !a->subtype
|| ascii_strcasecmp ("pgp-encrypted", a->subtype)
/* Move forward to the application/pgp-encrypted body. */
a = a->next;
- mutt_mktemp (tempfile);
- if (!(fpout = safe_fopen (tempfile, "w+"))) {
+ fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!fpout) {
if (s->flags & M_DISPLAY)
state_attach_puts (_("[-- Error: could not create temporary file! "
"--]\n"), s);
s->fpin = savefp;
}
- /*
+ /*
* if a multipart/signed is the _only_ sub-part of a
* multipart/encrypted, cache signature verification
* status.
: _("[-- End of PGP/MIME encrypted data --]\n"), s);
}
- mutt_free_body (&tattach);
+ body_list_wipe(&tattach);
}
- fclose (fpout);
+ m_fclose(&fpout);
mutt_unlink (tempfile);
- debug_print (2, ("Leaving pgp_encrypted handler\n"));
return (rc);
}
/* Support for application/smime */
-int smime_gpgme_application_handler (BODY * a, STATE * s)
+int crypt_smime_application_smime_handler (BODY * a, STATE * s)
{
char tempfile[_POSIX_PATH_MAX];
FILE *fpout;
int is_signed;
int rc = 0;
- debug_print (2, ("Entering smime_encrypted handler\n"));
-
a->warnsig = 0;
- mutt_mktemp (tempfile);
- if (!(fpout = safe_fopen (tempfile, "w+"))) {
+ fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!fpout) {
if (s->flags & M_DISPLAY)
state_attach_puts (_("[-- Error: could not create temporary file! "
"--]\n"), s);
s->fpin = savefp;
}
- /*
+ /*
* if a multipart/signed is the _only_ sub-part of a
* multipart/encrypted, cache signature verification
* status.
_("[-- End of S/MIME encrypted data --]\n"), s);
}
- mutt_free_body (&tattach);
+ body_list_wipe(&tattach);
}
- fclose (fpout);
+ m_fclose(&fpout);
mutt_unlink (tempfile);
- debug_print (2, ("Leaving smime_encrypted handler\n"));
return (rc);
}
/*
* Format an entry on the CRYPT key selection menu.
- *
+ *
* %n number
* %k key id %K key id of the principal key
* %u user id
* %[...] date of key using strftime(3)
*/
-static const char *crypt_entry_fmt (char *dest,
- size_t destlen,
- char op,
- const char *src,
- const char *prefix,
- const char *ifstring,
- const char *elsestring,
- unsigned long data, format_flag flags)
+static const char *
+crypt_entry_fmt (char *dest, ssize_t destlen, char op,
+ const char *src, const char *prefix,
+ const char *ifstr, const char *elstr,
+ anytype data, format_flag flags)
{
char fmt[16];
crypt_entry_t *entry;
const char *s = NULL;
unsigned long val;
- entry = (crypt_entry_t *) data;
+ entry = data.ptr;
key = entry->key;
/* if (isupper ((unsigned char) op)) */
case '[':
{
const char *cp;
- char buf2[SHORT_STRING], *p;
+ char buf2[STRING], *p;
int do_locales;
struct tm *tm;
- size_t len;
+ ssize_t len;
p = dest;
s = "x";
else {
gpgme_user_id_t uid = NULL;
- unsigned int i = 0;
+ int i = 0;
for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
i++, uid = uid->next);
*dest = '\0';
}
- if (optional)
- mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
- else if (flags & M_FORMAT_OPTIONAL)
- mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
- return (src);
+ if (flags & M_FORMAT_OPTIONAL)
+ m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
+ mutt_attach_fmt, data, 0);
+ return src;
}
/* Used by the display fucntion to format a line. */
-static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
+static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
{
crypt_key_t **key_table = (crypt_key_t **) menu->data;
crypt_entry_t entry;
entry.key = key_table[num];
entry.num = num + 1;
- mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
- (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
+ m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
+ option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
}
/* Compare two addresses and the keyid to be used for sorting. */
const unsigned char *string)
{
const unsigned char *s, *s1;
- size_t n;
+ ssize_t n;
unsigned char *p;
/* parse attributeType */
if (*string == '#') { /* hexstring */
string++;
- for (s = string; hexdigitp (s); s++)
+ for (s = string; hexval(*s) >= 0; s++)
s++;
n = s - string;
if (!n || (n & 1))
return NULL; /* empty or odd number of digits */
n /= 2;
- p = xmalloc(n + 1);
+ p = p_new(unsigned char, n + 1);
array->value = (char *) p;
for (s1 = string; n; s1 += 2, n--)
- *p++ = xtoi_2 (s1);
+ *p++ = (hexval(*s1) << 8) | hexval(*s1);
*p = 0;
}
else { /* regular v3 quoted string */
|| *s == '<' || *s == '>' || *s == '#' || *s == ';'
|| *s == '\\' || *s == '\"' || *s == ' ')
n++;
- else if (hexdigitp (s) && hexdigitp (s + 1)) {
+ else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
s++;
n++;
}
n++;
}
- p = xmalloc(n + 1);
+ p = p_new(unsigned char, n + 1);
array->value = (char *) p;
for (s = string; n; s++, n--) {
if (*s == '\\') {
s++;
- if (hexdigitp (s)) {
- *p++ = xtoi_2 (s);
+ if (hexval(*s) >= 0) {
+ *p++ = (hexval(*s) << 8) | hexval(*s + 1);
s++;
}
else
static struct dn_array_s *parse_dn (const unsigned char *string)
{
struct dn_array_s *array;
- size_t arrayidx, arraysize;
+ ssize_t arrayidx, arraysize;
int i;
arraysize = 7; /* C,ST,L,O,OU,CN,email */
const char *s = NULL, *s2 = NULL;
time_t tt = 0;
struct tm *tm;
- char shortbuf[SHORT_STRING];
+ char shortbuf[STRING];
unsigned long aval = 0;
const char *delim;
int is_pgp = 0;
gpgme_key_t k = NULL;
int maxdepth = 100;
- mutt_mktemp (tempfile);
- if (!(fp = safe_fopen (tempfile, "w"))) {
+ fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (!fp) {
mutt_perror (_("Can't create temporary file"));
-
return;
}
mutt_message _("Collecting data...");
leave:
gpgme_key_release (k);
gpgme_release (listctx);
- fclose (fp);
+ m_fclose(&fp);
mutt_clear_error ();
snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
mutt_do_pager (cmd, tempfile, 0, NULL);
}
-/*
- * Implementation of `findkeys'.
- */
+/* Implementation of `findkeys'. */
-
-/* Convert LIST into a pattern string suitable to be passed to GPGME.
+/* Convert string_list_t into a pattern string suitable to be passed to GPGME.
We need to convert spaces in an item into a '+' and '%' into
"%25". */
-static char *list_to_pattern (LIST * list)
+static char *list_to_pattern (string_list_t * list)
{
- LIST *l;
+ string_list_t *l;
char *pattern, *p;
const char *s;
- size_t n;
+ ssize_t n;
n = 0;
for (l = list; l; l = l->next) {
/* Return a list of keys which are candidates for the selection.
Select by looking at the HINTS list. */
-static crypt_key_t *get_candidates (LIST * hints, unsigned int app,
+static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
int secret)
{
crypt_key_t *db, *k, **kend;
depending on the protocol. For gpg we don' t need percent
escaped pappert but simple strings passed in an array to the
keylist_ext_start function. */
- LIST *l;
- size_t n;
+ string_list_t *l;
+ ssize_t n;
char **patarr;
for (l = hints, n = 0; l; l = l->next) {
if (key_check_cap (key, KEY_CAP_CAN_SIGN))
flags |= KEYFLAG_CANSIGN;
-#if 0 /* DISABLED code */
- if (!flags) {
- /* Bug in gpg. Capabilities are not listed for secret
- keys. Try to deduce them from the algorithm. */
-
- switch (key->subkeys[0].pubkey_algo) {
- case GPGME_PK_RSA:
- flags |= KEYFLAG_CANENCRYPT;
- flags |= KEYFLAG_CANSIGN;
- break;
- case GPGME_PK_ELG_E:
- flags |= KEYFLAG_CANENCRYPT;
- break;
- case GPGME_PK_DSA:
- flags |= KEYFLAG_CANSIGN;
- break;
- }
- }
-#endif /* DISABLED code */
-
for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
k = p_new(crypt_key_t, 1);
k->kobj = key;
/* Add the string STR to the list HINTS. This list is later used to
match addresses. */
-static LIST *crypt_add_string_to_hints (LIST * hints, const char *str)
+static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
{
char *scratch;
char *t;
crypt_key_t **key_table;
MUTTMENU *menu;
int i, done = 0;
- char helpstr[SHORT_STRING], buf[LONG_STRING];
+ char helpstr[STRING], buf[LONG_STRING];
crypt_key_t *k;
int (*f) (const void *, const void *);
int menu_to_use = 0;
helpstr[0] = 0;
mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT);
- strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
+ m_strcat(helpstr, sizeof(helpstr), buf);
mutt_make_help (buf, sizeof (buf), _("Select "), menu_to_use,
OP_GENERIC_SELECT_ENTRY);
- strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
+ m_strcat(helpstr, sizeof(helpstr), buf);
mutt_make_help (buf, sizeof (buf), _("Check key "),
menu_to_use, OP_VERIFY_KEY);
- strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
+ m_strcat(helpstr, sizeof(helpstr), buf);
mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
- strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
+ m_strcat(helpstr, sizeof(helpstr), buf);
menu = mutt_new_menu ();
menu->max = i;
else {
gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
gpgme_user_id_t uid = NULL;
- unsigned int j = 0;
+ int j = 0;
warn_s = "??";
unsigned int app, int *forced_valid)
{
address_t *r, *p;
- LIST *hints = NULL;
+ string_list_t *hints = NULL;
int weak = 0;
int invalid = 0;
mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
- mutt_free_list (&hints);
+ string_list_wipe(&hints);
if (!keys)
return NULL;
- debug_print (5, ("looking for %s <%s>.\n", a->personal, a->mailbox));
-
for (k = keys; k; k = k->next) {
- debug_print (5, (" looking at key: %s `%.15s'\n", crypt_keyid (k), k->uid));
-
if (abilities && !(k->flags & abilities)) {
- debug_print (5, (" insufficient abilities: Has %x, want %x\n", k->flags, abilities));
continue;
}
|| !(validity & CRYPT_KV_ADDR)))
this_key_has_weak = 1;
}
- address_delete (&r);
+ address_list_wipe(&r);
if (match) {
crypt_key_t *tmp;
if (matches) {
if (the_valid_key && !multi && !weak
&& !(invalid && option (OPTPGPSHOWUNUSABLE))) {
- /*
+ /*
* There was precisely one strong match on a valid ID, there
* were no valid keys with weak matches, and we aren't
* interested in seeing invalid keys.
- *
+ *
* Proceed without asking the user.
*/
k = crypt_copy_key (the_valid_key);
}
else {
- /*
+ /*
* Else: Ask the user.
*/
k = crypt_select_key (matches, a, NULL, app, forced_valid);
}
-static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
+static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
unsigned int app, int *forced_valid)
{
- LIST *hints = NULL;
+ string_list_t *hints = NULL;
crypt_key_t *keys;
crypt_key_t *matches = NULL;
crypt_key_t **matches_endp = &matches;
hints = crypt_add_string_to_hints (hints, p);
keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
- mutt_free_list (&hints);
+ string_list_wipe(&hints);
if (!keys)
return NULL;
continue;
match = 0;
- debug_print (5, ("matching \"%s\" against " "key %s, \"%s\":\n", p, crypt_keyid (k), k->uid));
if (!*p || !m_strcasecmp(p, crypt_keyid (k))
|| (!m_strncasecmp(p, "0x", 2)
|| m_stristr(k->uid, p)) {
crypt_key_t *tmp;
- debug_print (5, ("match.\n"));
-
*matches_endp = tmp = crypt_copy_key (k);
matches_endp = &tmp->next;
}
unsigned int app, int *forced_valid)
{
crypt_key_t *key;
- char resp[SHORT_STRING];
+ char resp[STRING];
struct crypt_cache *l = NULL;
int dummy;
static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
unsigned int app)
{
- char *keyID, *keylist = NULL, *t;
- size_t keylist_size = 0;
- size_t keylist_used = 0;
+ char *keylist = NULL, *t;
+ const char *keyID;
+ ssize_t keylist_size = 0;
+ ssize_t keylist_used = 0;
address_t *tmp = NULL, *addr = NULL;
address_t **last = &tmp;
address_t *p, *q;
last = &((*last)->next);
}
- if (fqdn)
- rfc822_qualify (tmp, fqdn);
-
- tmp = mutt_remove_duplicates (tmp);
+ rfc822_qualify(tmp, fqdn);
+ address_list_uniq(tmp);
for (p = tmp; p; p = p->next) {
char buf[LONG_STRING];
/* check for e-mail address */
if ((t = strchr (keyID, '@')) &&
(addr = rfc822_parse_adrlist (NULL, keyID))) {
- if (fqdn)
- rfc822_qualify (addr, fqdn);
+ rfc822_qualify(addr, fqdn);
q = addr;
}
else {
-#if 0
- k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
- *r_application, &forced_valid);
-#else
k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
app, &forced_valid);
-#endif
}
}
else if (r == -1) {
p_delete(&keylist);
- address_delete (&tmp);
- address_delete (&addr);
+ address_list_wipe(&tmp);
+ address_list_wipe(&addr);
return NULL;
}
}
snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
-#if 0
- *r_application,
-#else
app,
-#endif
&forced_valid)) == NULL) {
p_delete(&keylist);
- address_delete (&tmp);
- address_delete (&addr);
+ address_list_wipe(&tmp);
+ address_list_wipe(&addr);
return NULL;
}
}
{
const char *s = crypt_fpr (key);
-#if 0
- if (key->flags & KEYFLAG_ISX509)
- *r_application &= ~APPLICATION_PGP;
- if (!(key->flags & KEYFLAG_ISX509))
- *r_application &= ~APPLICATION_SMIME;
-#endif
-
keylist_size += m_strlen(s) + 4 + 1;
p_realloc(&keylist, keylist_size);
- sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
+ sprintf (keylist + keylist_used, "%s0x%s%s",
keylist_used ? " " : "", s, forced_valid ? "!" : "");
}
keylist_used = m_strlen(keylist);
crypt_free_key (&key);
- address_delete (&addr);
+ address_list_wipe(&addr);
}
- address_delete (&tmp);
+ address_list_wipe(&tmp);
return (keylist);
}
-char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
+int crypt_get_keys (HEADER * msg, char **keylist)
{
- return find_keys (to, cc, bcc, APPLICATION_PGP);
-}
+ /* Do a quick check to make sure that we can find all of the encryption
+ * keys if the user has requested this service.
+ */
-char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
-{
- return find_keys (to, cc, bcc, APPLICATION_SMIME);
-}
+ *keylist = NULL;
-/*
- * Implementation of `init'.
- */
+ if (msg->security & ENCRYPT) {
+ if (msg->security & APPLICATION_PGP) {
+ set_option(OPTPGPCHECKTRUST);
+ *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
+ APPLICATION_PGP);
+ unset_option(OPTPGPCHECKTRUST);
+ if (!*keylist)
+ return -1;
+ }
-/* Initialization. */
-static void init_gpgme (void)
-{
- /* Make sure that gpg-agent is running. */
- if (!getenv ("GPG_AGENT_INFO")) {
- mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
- if (mutt_any_key_to_continue (NULL) == -1)
- mutt_exit (1);
+ if (msg->security & APPLICATION_SMIME) {
+ *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
+ APPLICATION_SMIME);
+ if (!*keylist)
+ return -1;
+ }
}
-}
-void pgp_gpgme_init (void)
-{
- init_gpgme ();
+ return (0);
}
-void smime_gpgme_init (void)
-{
-}
-static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
+int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
{
crypt_key_t *p;
- char input_signas[SHORT_STRING];
+ char input_signas[STRING];
int choice;
if (msg->security & APPLICATION_PGP)
choice =
mutt_multi_choice (_
("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
- _("esabpfc"));
+ _("esabpc"));
else
choice =
mutt_multi_choice (_
("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
- _("esabmfc"));
+ _("esabmc"));
switch (choice) {
case 1: /* (e)ncrypt */
break;
case 3: /* sign (a)s */
-/* unset_option(OPTCRYPTCHECKTRUST); */
if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
is_smime ? APPLICATION_SMIME :
APPLICATION_PGP, NULL))) {
msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
}
-#if 0
- else {
- msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
- }
-#endif
*redraw = REDRAW_FULL;
break;
break;
case 6: /* (c)lear */
- msg->security = 0;
- break;
+ return msg->security = 0;
}
- if (choice == 6 || choice == 7);
- else if (is_smime) {
+ if (is_smime) {
msg->security &= ~APPLICATION_PGP;
msg->security |= APPLICATION_SMIME;
- }
- else {
+ } else {
msg->security &= ~APPLICATION_SMIME;
msg->security |= APPLICATION_PGP;
}
- return (msg->security);
-}
-
-int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
-{
- return gpgme_send_menu (msg, redraw, 0);
-}
-
-int smime_gpgme_send_menu (HEADER * msg, int *redraw)
-{
- return gpgme_send_menu (msg, redraw, 1);
+ return msg->security;
}
-static int verify_sender (HEADER * h, gpgme_protocol_t protocol)
+int crypt_smime_verify_sender (HEADER * h)
{
address_t *sender = NULL;
unsigned int ret = 1;
if (1 && (uid->email[0] == '<')
&& (uid->email[uid_length - 1] == '>')
&& (uid_length == sender_length + 2)
- && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
+ && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
ret = 0;
}
}
return ret;
}
-int smime_gpgme_verify_sender (HEADER * h)
+void crypt_invoke_import(FILE *stream, int smime)
+{
+ gpgme_ctx_t ctx = create_gpgme_context(smime);
+ gpgme_data_t data;
+ gpgme_error_t err;
+
+ err = gpgme_data_new_from_stream(&data, stream);
+ if (err) {
+ mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
+ gpgme_release(ctx);
+ return;
+ }
+
+ err = gpgme_op_import(ctx, data);
+ if (err) {
+ mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
+ gpgme_data_release(data);
+ gpgme_release(ctx);
+ return;
+ }
+
+ gpgme_data_release(data);
+ gpgme_release(ctx);
+ return;
+}
+
+static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
+{
+ STATE s;
+ FILE *tmpfp = tmpfile();
+
+ if (tmpfp == NULL) {
+ mutt_perror (_("Can't create temporary file"));
+ return;
+ }
+
+ p_clear(&s, 1);
+ s.fpin = fp;
+ s.fpout = tmpfp;
+ mutt_body_handler(top, &s);
+
+ rewind(tmpfp);
+ crypt_invoke_import(tmpfp, 0);
+ m_fclose(&tmpfp);
+}
+
+void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
+{
+ mutt_endwin (NULL);
+ set_option (OPTDONTHANDLEPGPKEYS);
+
+ for (; top; top = top->next) {
+ if (!tag || top->tagged)
+ pgp_extract_keys_from_attachment (fp, top);
+
+ if (!tag)
+ break;
+ }
+
+ unset_option (OPTDONTHANDLEPGPKEYS);
+}
+
+
+/* TODO */
+
+/* fixme: needs documentation. */
+void crypt_pgp_invoke_getkeys (address_t * addr)
+{
+}
+
+/* Generate a PGP public key attachment. */
+BODY *crypt_pgp_make_key_attachment (char *tempf)
+{
+ return NULL;
+}
+
+/* S/MIME */
+
+/* fixme: Needs documentation. */
+void crypt_smime_getkeys (ENVELOPE * env)
{
- return verify_sender (h, GPGME_PROTOCOL_CMS);
}
-#endif