[gmime] Reimplemented GMimeGpgContext using GpgMe



commit af138de4adbcec091e0bd3855be2e207420efbdd
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Sun Feb 5 21:26:14 2017 -0500

    Reimplemented GMimeGpgContext using GpgMe

 gmime/gmime-gpg-context.c   | 2378 ++++++++-----------------------------------
 gmime/gmime-gpg-context.h   |    5 +-
 gmime/gmime-pkcs7-context.c |    2 -
 tests/test-pgp.c            |    2 +-
 tests/test-pgpmime.c        |    8 +-
 tests/testsuite.c           |   56 +-
 6 files changed, 509 insertions(+), 1942 deletions(-)
---
diff --git a/gmime/gmime-gpg-context.c b/gmime/gmime-gpg-context.c
index 9f5b026..e2b4242 100644
--- a/gmime/gmime-gpg-context.c
+++ b/gmime/gmime-gpg-context.c
@@ -23,29 +23,9 @@
 #include <config.h>
 #endif
 
-#ifdef __APPLE__
-#undef HAVE_POLL_H
-#undef HAVE_POLL
-typedef unsigned int nfds_t;
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <termios.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
 
 #include "gmime-gpg-context.h"
 #ifdef ENABLE_CRYPTO
@@ -58,6 +38,8 @@ typedef unsigned int nfds_t;
 #endif /* ENABLE_CRYPTO */
 #include "gmime-error.h"
 
+#include <gpgme.h>
+
 #ifdef ENABLE_DEBUG
 #define d(x) x
 #else
@@ -80,22 +62,18 @@ typedef unsigned int nfds_t;
 
 /**
  * GMimeGpgContext:
- * @parent_object: parent #GMimeCryptoContext
- * @auto_key_retrieve: %TRUE if gpg should automatically retrieve unknown keys from the web
- * @use_agent: %TRUE if gpg should use the gpg-agent for requesting passphrases
- * @path: path to gpg
- * @version: The GnuPG version.
  *
  * A GnuPG crypto context.
  **/
 struct _GMimeGpgContext {
        GMimeCryptoContext parent_object;
+       
+#ifdef ENABLE_CRYPTO
+       gpgme_encrypt_flags_t encrypt_flags;
        gboolean retrieve_session_key;
        gboolean auto_key_retrieve;
-       gboolean always_trust;
-       gboolean use_agent;
-       int version;
-       char *path;
+       gpgme_ctx_t ctx;
+#endif
 };
 
 struct _GMimeGpgContextClass {
@@ -205,21 +183,25 @@ g_mime_gpg_context_class_init (GMimeGpgContextClass *klass)
 }
 
 static void
-g_mime_gpg_context_init (GMimeGpgContext *ctx, GMimeGpgContextClass *klass)
+g_mime_gpg_context_init (GMimeGpgContext *gpg, GMimeGpgContextClass *klass)
 {
-       ctx->retrieve_session_key = FALSE;
-       ctx->auto_key_retrieve = FALSE;
-       ctx->always_trust = FALSE;
-       ctx->use_agent = FALSE;
-       ctx->path = NULL;
+#ifdef ENABLE_CRYPTO
+       gpg->retrieve_session_key = FALSE;
+       gpg->auto_key_retrieve = FALSE;
+       gpg->encrypt_flags = 0;
+       gpg->ctx = NULL;
+#endif
 }
 
 static void
 g_mime_gpg_context_finalize (GObject *object)
 {
-       GMimeGpgContext *ctx = (GMimeGpgContext *) object;
+       GMimeGpgContext *gpg = (GMimeGpgContext *) object;
        
-       g_free (ctx->path);
+#ifdef ENABLE_CRYPTO
+       if (gpg->ctx)
+               gpgme_release (gpg->ctx);
+#endif
        
        G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -309,1742 +291,401 @@ gpg_get_key_exchange_protocol (GMimeCryptoContext *ctx)
 }
 
 #ifdef ENABLE_CRYPTO
-enum _GpgCtxMode {
-       GPG_CTX_MODE_SIGN,
-       GPG_CTX_MODE_VERIFY,
-       GPG_CTX_MODE_ENCRYPT,
-       GPG_CTX_MODE_SIGN_ENCRYPT,
-       GPG_CTX_MODE_DECRYPT,
-       GPG_CTX_MODE_IMPORT,
-       GPG_CTX_MODE_EXPORT,
-};
-
-struct _GpgCtx {
-       enum _GpgCtxMode mode;
-       GHashTable *userid_hint;
-       GMimeGpgContext *ctx;
-       pid_t pid;
-       
-       char *userid;
-       GPtrArray *recipients;
-       GMimeCipherAlgo cipher;
-       GMimeDigestAlgo digest;
-       
-       int stdin_fd;
-       int stdout_fd;
-       int stderr_fd;
-       int status_fd;
-       int secret_fd;  /* used for exactly one of:
-                        * (a) sending a password to gpg when signing or encrypting
-                        * (b) sending a detatched signature to gpg when verifying
-                        */
-       
-       /* status-fd buffer */
-       char *statusbuf;
-       char *statusptr;
-       guint statusleft;
-       
-       char *need_id;
-       
-       GMimeStream *sigstream;
-       GMimeStream *istream;
-       GMimeStream *ostream;
-       
-       GByteArray *diag;
-       GMimeStream *diagnostics;
-       
-       GMimeCertificateList *encrypted_to;  /* full list of encrypted-to recipients */
-       GMimeSignatureList *signatures;
-       GMimeSignature *signature;
-       char *session_key;
-       
-       int exit_status;
-       
-       unsigned int utf8:1;
-       unsigned int exited:1;
-       unsigned int complete:1;
-       unsigned int seen_eof1:1;
-       unsigned int seen_eof2:1;
-       unsigned int flushed:1;      /* flushed the diagnostics stream (aka stderr) */
-       unsigned int always_trust:1;
-       unsigned int use_agent:1;
-       unsigned int armor:1;
-       unsigned int need_passwd:1;
-       unsigned int bad_passwds:2;
-       unsigned int decrypt_okay:1;
-       unsigned int override_session_key:1;
-       
-       unsigned int padding:18;
-};
-
-static struct _GpgCtx *
-gpg_ctx_new (GMimeGpgContext *ctx)
+static gpgme_error_t
+gpg_passphrase_cb (void *hook, const char *uid_hint, const char *passphrase_info, int prev_was_bad, int fd)
 {
-       struct _GpgCtx *gpg;
-       const char *charset;
+       GMimeCryptoContext *context = (GMimeCryptoContext *) hook;
        GMimeStream *stream;
+       gpgme_error_t error;
+       GError *err = NULL;
+       gboolean rv;
        
-       gpg = g_slice_new (struct _GpgCtx);
-       gpg->mode = GPG_CTX_MODE_SIGN;
-       gpg->ctx = ctx;
-       gpg->userid_hint = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-       gpg->decrypt_okay = FALSE;
-       gpg->complete = FALSE;
-       gpg->seen_eof1 = TRUE;
-       gpg->seen_eof2 = FALSE;
-       gpg->pid = (pid_t) -1;
-       gpg->exit_status = 0;
-       gpg->flushed = FALSE;
-       gpg->exited = FALSE;
-       
-       gpg->userid = NULL;
-       gpg->recipients = NULL;
-       gpg->cipher = GMIME_CIPHER_ALGO_DEFAULT;
-       gpg->digest = GMIME_DIGEST_ALGO_DEFAULT;
-       gpg->override_session_key = FALSE;
-       gpg->always_trust = FALSE;
-       gpg->use_agent = FALSE;
-       gpg->armor = FALSE;
-       
-       gpg->stdin_fd = -1;
-       gpg->stdout_fd = -1;
-       gpg->stderr_fd = -1;
-       gpg->status_fd = -1;
-       gpg->secret_fd = -1;
-       
-       gpg->statusbuf = g_malloc (128);
-       gpg->statusptr = gpg->statusbuf;
-       gpg->statusleft = 128;
-       
-       gpg->bad_passwds = 0;
-       gpg->need_passwd = FALSE;
-       gpg->need_id = NULL;
-       
-       gpg->encrypted_to = NULL;
-       gpg->session_key = NULL;
-       gpg->signatures = NULL;
-       gpg->signature = NULL;
-       
-       gpg->sigstream = NULL;
-       gpg->istream = NULL;
-       gpg->ostream = NULL;
-       
-       stream = g_mime_stream_mem_new ();
-       gpg->diag = GMIME_STREAM_MEM (stream)->buffer;
-       charset = g_mime_charset_iconv_name (g_mime_locale_charset ());
-       if (g_ascii_strcasecmp (charset, "UTF-8") != 0) {
-               GMimeStream *fstream;
-               GMimeFilter *filter;
-               
-               fstream = g_mime_stream_filter_new (stream);
-               filter = g_mime_filter_charset_new (charset, "UTF-8");
-               g_mime_stream_filter_add ((GMimeStreamFilter *) fstream, filter);
+       if (context->request_passwd) {
+               stream = g_mime_stream_pipe_new (fd);
+               rv = context->request_passwd (context, uid_hint, passphrase_info, prev_was_bad, stream, &err);
                g_object_unref (stream);
-               g_object_unref (filter);
-               
-               gpg->diagnostics = fstream;
-               
-               gpg->utf8 = FALSE;
        } else {
-               /* system charset is UTF-8, shouldn't need any conversion */
-               gpg->diagnostics = stream;
-               
-               gpg->utf8 = TRUE;
+               return GPG_ERR_GENERAL;
        }
        
-       return gpg;
-}
-
-static void
-gpg_ctx_set_mode (struct _GpgCtx *gpg, enum _GpgCtxMode mode)
-{
-       gpg->mode = mode;
-       
-       switch (gpg->mode) {
-       case GPG_CTX_MODE_SIGN_ENCRYPT:
-       case GPG_CTX_MODE_DECRYPT:
-       case GPG_CTX_MODE_SIGN:
-               gpg->need_passwd = TRUE;
-               break;
-       default:
-               gpg->need_passwd = FALSE;
-               break;
+       if (!rv) {
+               error = GPG_ERR_CANCELED;
+               g_error_free (err);
+       } else {
+               error = GPG_ERR_NO_ERROR;
        }
+       
+       return error;
 }
 
-static void
-gpg_ctx_set_digest (struct _GpgCtx *gpg, GMimeDigestAlgo digest)
-{
-       gpg->digest = digest;
-}
-
-static void
-gpg_ctx_set_always_trust (struct _GpgCtx *gpg, gboolean trust)
+static ssize_t
+gpg_stream_read (void *stream, void *buffer, size_t size)
 {
-       gpg->always_trust = trust;
+       return g_mime_stream_read ((GMimeStream *) stream, (char *) buffer, size);
 }
 
-static void
-gpg_ctx_set_use_agent (struct _GpgCtx *gpg, gboolean use_agent)
+static ssize_t
+gpg_stream_write (void *stream, const void *buffer, size_t size)
 {
-       gpg->use_agent = use_agent;
+       return g_mime_stream_write ((GMimeStream *) stream, (const char *) buffer, size);
 }
 
-static void
-gpg_ctx_set_userid (struct _GpgCtx *gpg, const char *userid)
+static off_t
+gpg_stream_seek (void *stream, off_t offset, int whence)
 {
-       g_free (gpg->userid);
-       gpg->userid = g_strdup (userid);
+       switch (whence) {
+       case SEEK_SET:
+               return (off_t) g_mime_stream_seek ((GMimeStream *) stream, (gint64) offset, 
GMIME_STREAM_SEEK_SET);
+       case SEEK_CUR:
+               return (off_t) g_mime_stream_seek ((GMimeStream *) stream, (gint64) offset, 
GMIME_STREAM_SEEK_CUR);
+       case SEEK_END:
+               return (off_t) g_mime_stream_seek ((GMimeStream *) stream, (gint64) offset, 
GMIME_STREAM_SEEK_END);
+       default:
+               return -1;
+       }
 }
 
 static void
-gpg_ctx_add_recipient (struct _GpgCtx *gpg, const char *keyid)
+gpg_stream_free (void *stream)
 {
-       if (gpg->mode != GPG_CTX_MODE_ENCRYPT &&
-           gpg->mode != GPG_CTX_MODE_SIGN_ENCRYPT &&
-           gpg->mode != GPG_CTX_MODE_EXPORT)
-               return;
-       
-       if (!gpg->recipients)
-               gpg->recipients = g_ptr_array_new ();
-       
-       g_ptr_array_add (gpg->recipients, g_strdup (keyid));
+       /* no-op */
 }
 
-static void
-gpg_ctx_set_armor (struct _GpgCtx *gpg, gboolean armor)
-{
-       gpg->armor = armor;
-}
+static struct gpgme_data_cbs gpg_stream_funcs = {
+       gpg_stream_read,
+       gpg_stream_write,
+       gpg_stream_seek,
+       gpg_stream_free
+};
 
-static void
-gpg_ctx_set_istream (struct _GpgCtx *gpg, GMimeStream *istream)
-{
-       g_object_ref (istream);
-       if (gpg->istream)
-               g_object_unref (gpg->istream);
-       gpg->istream = istream;
-}
 
-static void
-gpg_ctx_set_ostream (struct _GpgCtx *gpg, GMimeStream *ostream)
-{
-       g_object_ref (ostream);
-       if (gpg->ostream)
-               g_object_unref (gpg->ostream);
-       gpg->ostream = ostream;
-       gpg->seen_eof1 = FALSE;
-}
 
-static void
-gpg_ctx_set_sigstream (struct _GpgCtx *gpg, GMimeStream *sigstream)
-{
-       g_object_ref (sigstream);
-       if (gpg->sigstream)
-               g_object_unref (gpg->sigstream);
-       gpg->sigstream = sigstream;
-}
+#define KEY_IS_OK(k)   (!((k)->expired || (k)->revoked ||      \
+                          (k)->disabled || (k)->invalid))
 
-static const char *
-gpg_ctx_get_diagnostics (struct _GpgCtx *gpg)
+static gpgme_key_t
+gpg_get_key_by_name (GMimeGpgContext *gpg, const char *name, gboolean secret, GError **err)
 {
-       if (!gpg->flushed) {
-               g_mime_stream_flush (gpg->diagnostics);
-               g_byte_array_append (gpg->diag, (unsigned char *) "", 1);
-               gpg->flushed = TRUE;
+       time_t now = time (NULL);
+       gpgme_key_t key = NULL;
+       gpgme_subkey_t subkey;
+       gboolean bad = FALSE;
+       gpgme_error_t error;
+       int errval = 0;
+       
+       if ((error = gpgme_op_keylist_start (gpg->ctx, name, secret)) != GPG_ERR_NO_ERROR) {
+               if (secret)
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list secret keys for 
\"%s\""), name);
+               else
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list keys for \"%s\""), 
name);
+               return NULL;
        }
        
-       return (const char *) gpg->diag->data;
-}
-
-static void
-gpg_ctx_free (struct _GpgCtx *gpg)
-{
-       guint i;
-       
-       g_hash_table_destroy (gpg->userid_hint);
-       
-       g_free (gpg->userid);
-       
-       if (gpg->recipients) {
-               for (i = 0; i < gpg->recipients->len; i++)
-                       g_free (gpg->recipients->pdata[i]);
-       
-               g_ptr_array_free (gpg->recipients, TRUE);
+       while ((error = gpgme_op_keylist_next (gpg->ctx, &key)) == GPG_ERR_NO_ERROR) {
+               /* check if this key and the relevant subkey are usable */
+               if (KEY_IS_OK (key)) {
+                       subkey = key->subkeys;
+                       
+                       while (subkey && ((secret && !subkey->can_sign) ||
+                                         (!secret && !subkey->can_encrypt)))
+                               subkey = subkey->next;
+                       
+                       if (subkey && KEY_IS_OK (subkey) && 
+                           (subkey->expires == 0 || subkey->expires > now))
+                               break;
+                       
+                       if (subkey->expired)
+                               errval = GPG_ERR_KEY_EXPIRED;
+                       else
+                               errval = GPG_ERR_BAD_KEY;
+               } else {
+                       if (key->expired)
+                               errval = GPG_ERR_KEY_EXPIRED;
+                       else
+                               errval = GPG_ERR_BAD_KEY;
+               }
+               
+               gpgme_key_unref (key);
+               bad = TRUE;
+               key = NULL;
        }
        
-       if (gpg->stdin_fd != -1)
-               close (gpg->stdin_fd);
-       if (gpg->stdout_fd != -1)
-               close (gpg->stdout_fd);
-       if (gpg->stderr_fd != -1)
-               close (gpg->stderr_fd);
-       if (gpg->status_fd != -1)
-               close (gpg->status_fd);
-       if (gpg->secret_fd != -1)
-               close (gpg->secret_fd);
-       
-       g_free (gpg->statusbuf);
-       
-       g_free (gpg->need_id);
-       
-       if (gpg->sigstream)
-               g_object_unref (gpg->sigstream);
+       gpgme_op_keylist_end (gpg->ctx);
        
-       if (gpg->istream)
-               g_object_unref (gpg->istream);
-       
-       if (gpg->ostream)
-               g_object_unref (gpg->ostream);
-       
-       g_object_unref (gpg->diagnostics);
-       
-       if (gpg->encrypted_to)
-               g_object_unref (gpg->encrypted_to);
-       
-       if (gpg->session_key) {
-               memset (gpg->session_key, 0, strlen (gpg->session_key));
-               g_free (gpg->session_key);
+       if (error != GPG_ERR_NO_ERROR && error != GPG_ERR_EOF) {
+               if (secret)
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list secret keys for 
\"%s\""), name);
+               else
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list keys for \"%s\""), 
name);
+               
+               return NULL;
        }
        
-       if (gpg->signatures)
-               g_object_unref (gpg->signatures);
-       
-       g_slice_free (struct _GpgCtx, gpg);
-}
-
-static const char *
-gpg_digest_str (GMimeDigestAlgo digest)
-{
-       switch (digest) {
-       case GMIME_DIGEST_ALGO_MD2:
-               return "--digest-algo=MD2";
-       case GMIME_DIGEST_ALGO_MD5:
-               return "--digest-algo=MD5";
-       case GMIME_DIGEST_ALGO_SHA1:
-               return "--digest-algo=SHA1";
-       case GMIME_DIGEST_ALGO_SHA224:
-               return "--digest-algo=SHA224";
-       case GMIME_DIGEST_ALGO_SHA256:
-               return "--digest-algo=SHA256";
-       case GMIME_DIGEST_ALGO_SHA384:
-               return "--digest-algo=SHA384";
-       case GMIME_DIGEST_ALGO_SHA512:
-               return "--digest-algo=SHA512";
-       case GMIME_DIGEST_ALGO_RIPEMD160:
-               return "--digest-algo=RIPEMD160";
-       case GMIME_DIGEST_ALGO_TIGER192:
-               return "--digest-algo=TIGER192";
-       case GMIME_DIGEST_ALGO_MD4:
-               return "--digest-algo=MD4";
-       default:
+       if (!key) {
+               if (strchr (name, '@')) {
+                       if (bad)
+                               g_set_error (err, GMIME_GPGME_ERROR, errval,
+                                            _("A key for %s is present, but it is expired, disabled, revoked 
or invalid"),
+                                            name);
+                       else
+                               g_set_error (err, GMIME_GPGME_ERROR, GPG_ERR_NOT_FOUND,
+                                            _("Could not find a key for %s"), name);
+               } else {
+                       if (bad)
+                               g_set_error (err, GMIME_GPGME_ERROR, errval,
+                                            _("A key with id %s is present, but it is expired, disabled, 
revoked or invalid"),
+                                            name);
+                       else
+                               g_set_error (err, GMIME_GPGME_ERROR, GPG_ERR_NOT_FOUND,
+                                            _("Could not find a key with id %s"), name);
+               }
+               
                return NULL;
        }
-}
-
-static const char *
-filename (const char *path)
-{
-       const char *slash = strrchr (path, '/');
        
-       return slash != NULL ? slash + 1 : path;
+       return key;
 }
 
-static char **
-gpg_ctx_get_argv (struct _GpgCtx *gpg, const char *path, int status_fd, int secret_fd, char ***strv)
+static gboolean
+gpg_add_signer (GMimeGpgContext *gpg, const char *signer, GError **err)
 {
-       const char *digest_str;
-       char **argv, *buf;
-       GPtrArray *args;
-       int v = 0;
-       guint i;
-       
-       *strv = g_new (char *, 3);
-       
-       args = g_ptr_array_new ();
-       g_ptr_array_add (args, (char *) filename (path));
-       
-       g_ptr_array_add (args, "--verbose");
-       g_ptr_array_add (args, "--no-secmem-warning");
-       g_ptr_array_add (args, "--no-greeting");
-       g_ptr_array_add (args, "--no-tty");
-       
-       if (!gpg->need_passwd) {
-               /* only use batch mode if we don't intend on using the
-                   interactive --command-fd option to send it the
-                   user's password */
-               g_ptr_array_add (args, "--batch");
-       }
-       
-       g_ptr_array_add (args, "--charset=UTF-8");
-       
-       (*strv)[v++] = buf = g_strdup_printf ("--status-fd=%d", status_fd);
-       g_ptr_array_add (args, buf);
-       
-       if (gpg->need_passwd && !gpg->override_session_key) {
-               (*strv)[v++] = buf = g_strdup_printf ("--command-fd=%d", secret_fd);
-               g_ptr_array_add (args, buf);
-       }
-       
-       switch (gpg->mode) {
-       case GPG_CTX_MODE_SIGN:
-               if (gpg->use_agent)
-                       g_ptr_array_add (args, "--use-agent");
-               
-               g_ptr_array_add (args, "--sign");
-               g_ptr_array_add (args, "--detach");
-               if (gpg->armor)
-                       g_ptr_array_add (args, "--armor");
-               if ((digest_str = gpg_digest_str (gpg->digest)))
-                       g_ptr_array_add (args, (char *) digest_str);
-               if (gpg->userid) {
-                       g_ptr_array_add (args, "-u");
-                       g_ptr_array_add (args, (char *) gpg->userid);
-               }
-               g_ptr_array_add (args, "--output");
-               g_ptr_array_add (args, "-");
-               break;
-       case GPG_CTX_MODE_VERIFY:
-               if (!gpg->ctx->auto_key_retrieve) {
-                       g_ptr_array_add (args, "--keyserver-options");
-                       g_ptr_array_add (args, "no-auto-key-retrieve");
-               }
-               
-               g_ptr_array_add (args, "--enable-special-filenames");
-               g_ptr_array_add (args, "--verify");
-               g_ptr_array_add (args, "--");
-               
-               /* signature stream must come first */
-               (*strv)[v++] = buf = g_strdup_printf ("-&%d", secret_fd);
-               g_ptr_array_add (args, buf);
-               
-               /* followed by the content stream (in this case, stdin) */
-               g_ptr_array_add (args, "-");
-               break;
-       case GPG_CTX_MODE_SIGN_ENCRYPT:
-               if (gpg->use_agent)
-                       g_ptr_array_add (args, "--use-agent");
-               
-               g_ptr_array_add (args, "--sign");
-               
-               if ((digest_str = gpg_digest_str (gpg->digest)))
-                       g_ptr_array_add (args, (char *) digest_str);
-               
-               /* fall thru... */
-       case GPG_CTX_MODE_ENCRYPT:
-               g_ptr_array_add (args, "--encrypt");
-               
-               if (gpg->armor)
-                       g_ptr_array_add (args, "--armor");
-               
-               if (gpg->always_trust)
-                       g_ptr_array_add (args, "--always-trust");
-               
-               if (gpg->userid) {
-                       g_ptr_array_add (args, "-u");
-                       g_ptr_array_add (args, (char *) gpg->userid);
-               }
-               
-               if (gpg->recipients) {
-                       for (i = 0; i < gpg->recipients->len; i++) {
-                               g_ptr_array_add (args, "-r");
-                               g_ptr_array_add (args, gpg->recipients->pdata[i]);
-                       }
-               }
-               g_ptr_array_add (args, "--output");
-               g_ptr_array_add (args, "-");
-               break;
-       case GPG_CTX_MODE_DECRYPT:
-               if (gpg->use_agent)
-                       g_ptr_array_add (args, "--use-agent");
-               
-               if (gpg->ctx->retrieve_session_key)
-                       g_ptr_array_add (args, "--show-session-key");
-               
-               if (gpg->override_session_key) {
-                       (*strv)[v++] = buf = g_strdup_printf ("--override-session-key-fd=%d", secret_fd);
-                       g_ptr_array_add (args, buf);
-               }
-               
-               g_ptr_array_add (args, "--decrypt");
-               g_ptr_array_add (args, "--output");
-               g_ptr_array_add (args, "-");
-               break;
-       case GPG_CTX_MODE_IMPORT:
-               g_ptr_array_add (args, "--import");
-               g_ptr_array_add (args, "-");
-               break;
-       case GPG_CTX_MODE_EXPORT:
-               if (gpg->armor)
-                       g_ptr_array_add (args, "--armor");
-               g_ptr_array_add (args, "--export");
-               for (i = 0; i < gpg->recipients->len; i++)
-                       g_ptr_array_add (args, gpg->recipients->pdata[i]);
-               break;
-       }
-       
-#if d(!)0
-       for (i = 0; i < args->len; i++)
-               printf ("%s ", (char *) args->pdata[i]);
-       printf ("\n");
-#endif
+       gpgme_key_t key = NULL;
        
-       g_ptr_array_add (args, NULL);
-       (*strv)[v] = NULL;
+       if (!(key = gpg_get_key_by_name (gpg, signer, TRUE, err)))
+               return FALSE;
        
-       argv = (char **) args->pdata;
-       g_ptr_array_free (args, FALSE);
+       /* set the key (the previous operation guaranteed that it exists, no need
+        * 2 check return values...) */
+       gpgme_signers_add (gpg->ctx, key);
+       gpgme_key_unref (key);
        
-       return argv;
+       return TRUE;
 }
+#endif /* ENABLE_CRYPTO */
 
 static int
-gpg_ctx_op_start (struct _GpgCtx *gpg, const char *path)
+gpg_sign (GMimeCryptoContext *context, const char *userid, GMimeDigestAlgo digest,
+         GMimeStream *istream, GMimeStream *ostream, GError **err)
 {
-       int i, maxfd, errnosave, fds[10];
-       char **argv, **strv = NULL;
-       int flags;
+#ifdef ENABLE_CRYPTO
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
+       gpgme_sign_result_t result;
+       gpgme_data_t input, output;
+       gpgme_error_t error;
        
-       maxfd = G_N_ELEMENTS (fds);
-       for (i = 0; i < maxfd; i++)
-               fds[i] = -1;
+       if (!gpg_add_signer (gpg, userid, err))
+               return -1;
        
-       /* don't create the command-fd if we don't need it */
-       if (!(gpg->need_passwd || gpg->sigstream || gpg->override_session_key))
-               maxfd -= 2;
+       gpgme_set_armor (gpg->ctx, FALSE);
        
-       for (i = 0; i < maxfd; i += 2) {
-               if (pipe (fds + i) == -1)
-                       goto exception;
+       if ((error = gpgme_data_new_from_cbs (&input, &gpg_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
+               return -1;
        }
        
-       argv = gpg_ctx_get_argv (gpg, path, fds[7], fds[8], &strv);
-       
-       if (!(gpg->pid = fork ())) {
-               /* child process */
-               
-               if ((dup2 (fds[0], STDIN_FILENO) < 0) ||
-                   (dup2 (fds[3], STDOUT_FILENO) < 0) ||
-                   (dup2 (fds[5], STDERR_FILENO) < 0)) {
-                       _exit (255);
-               }
-               
-               /* Dissociate from gmime's controlling terminal so
-                * that gpg won't be able to read from it.
-                */
-               setsid ();
-               
-               maxfd = sysconf (_SC_OPEN_MAX);
-               for (i = 3; i < maxfd; i++) {
-                       /* don't close the status-fd or the passwd-fd */
-                       if (i != fds[7] && i != fds[8])
-                               fcntl (i, F_SETFD, FD_CLOEXEC);
-               }
-               
-               /* run gpg */
-               execvp (gpg->ctx->path, argv);
-               _exit (255);
-       } else if (gpg->pid < 0) {
-               g_strfreev (strv);
-               g_free (argv);
-               goto exception;
+       if ((error = gpgme_data_new_from_cbs (&output, &gpg_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
+               gpgme_data_release (input);
+               return -1;
        }
        
-       /* parent process */
-       
-       g_strfreev (strv);
-       g_free (argv);
-       
-       close (fds[0]);
-       gpg->stdin_fd = fds[1];
-       gpg->stdout_fd = fds[2];
-       close (fds[3]);
-       gpg->stderr_fd = fds[4];
-       close (fds[5]);
-       gpg->status_fd = fds[6];
-       close (fds[7]);
-       
-       if (fds[8] != -1) {
-               flags = (flags = fcntl (fds[9], F_GETFL)) == -1 ? O_WRONLY : flags;
-               fcntl (fds[9], F_SETFL, flags | O_NONBLOCK);
-               gpg->secret_fd = fds[9];
-               close (fds[8]);
+       /* sign the input stream */
+       if ((error = gpgme_op_sign (gpg->ctx, input, output, GPGME_SIG_MODE_DETACH)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Signing failed"));
+               gpgme_data_release (output);
+               gpgme_data_release (input);
+               return -1;
        }
        
-       flags = (flags = fcntl (gpg->stdin_fd, F_GETFL)) == -1 ? O_WRONLY : flags;
-       fcntl (gpg->stdin_fd, F_SETFL, flags | O_NONBLOCK);
-       
-       flags = (flags = fcntl (gpg->stdout_fd, F_GETFL)) == -1 ? O_RDONLY : flags;
-       fcntl (gpg->stdout_fd, F_SETFL, flags | O_NONBLOCK);
-       
-       flags = (flags = fcntl (gpg->stderr_fd, F_GETFL)) == -1 ? O_RDONLY : flags;
-       fcntl (gpg->stderr_fd, F_SETFL, flags | O_NONBLOCK);
+       gpgme_data_release (output);
+       gpgme_data_release (input);
        
-       flags = (flags = fcntl (gpg->status_fd, F_GETFL)) == -1 ? O_RDONLY : flags;
-       fcntl (gpg->status_fd, F_SETFL, flags | O_NONBLOCK);
-       
-       return 0;
+       /* return the digest algorithm used for signing */
+       result = gpgme_op_sign_result (gpg->ctx);
        
- exception:
-       
-       errnosave = errno;
-       
-       for (i = 0; i < maxfd; i++) {
-               if (fds[i] != -1)
-                       close (fds[i]);
-       }
-       
-       errno = errnosave;
+       return gpg_digest_id (context, gpgme_hash_algo_name (result->signatures->hash_algo));
+#else
+       g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("PGP support is not enabled in this 
build"));
        
        return -1;
+#endif /* ENABLE_CRYPTO */
 }
 
-static char *
-next_token (char *in, gboolean secret, char **token)
+#ifdef ENABLE_CRYPTO
+static GMimeCertificateTrust
+gpg_trust (gpgme_validity_t trust)
 {
-       char *start, *inptr = in;
-       
-       while (*inptr == ' ')
-               inptr++;
-       
-       if (*inptr == '\0' || *inptr == '\n') {
-               if (token)
-                       *token = NULL;
-               return inptr;
+       switch (trust) {
+       case GPGME_VALIDITY_UNKNOWN:
+       default:
+               return GMIME_CERTIFICATE_TRUST_NONE;
+       case GPGME_VALIDITY_UNDEFINED:
+               return GMIME_CERTIFICATE_TRUST_UNDEFINED;
+       case GPGME_VALIDITY_NEVER:
+               return GMIME_CERTIFICATE_TRUST_NEVER;
+       case GPGME_VALIDITY_MARGINAL:
+               return GMIME_CERTIFICATE_TRUST_MARGINAL;
+       case GPGME_VALIDITY_FULL:
+               return GMIME_CERTIFICATE_TRUST_FULLY;
+       case GPGME_VALIDITY_ULTIMATE:
+               return GMIME_CERTIFICATE_TRUST_ULTIMATE;
        }
-       
-       start = inptr;
-       while (*inptr && *inptr != ' ' && *inptr != '\n')
-               inptr++;
-       
-       if (token != NULL)
-               *token = g_strndup (start, (size_t) (inptr - start));
-       
-       if (secret)
-               memset (start, '*', (size_t) (inptr - start));
-       
-       return inptr;
 }
 
-/**
- * gpg_ctx_add_signature:
- * @gpg: GnuPG context
- * @status: a #GMimeSignatureStatus
- * @info: a string with the signature info
- *
- * Parses GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, and REVKEYSIG status messages
- * into a newly allocated #GMimeSignature and adds it to @gpg's signature list.
- **/
-static void
-gpg_ctx_add_signature (struct _GpgCtx *gpg, GMimeSignatureStatus status, char *info)
+static GMimeSignatureList *
+gpg_get_signatures (GMimeGpgContext *gpg, gboolean verify)
 {
-       GMimeSignature *sig;
-       
-       if (!gpg->signatures)
-               gpg->signatures = g_mime_signature_list_new ();
+       GMimeSignatureList *signatures;
+       GMimeSignature *signature;
+       gpgme_verify_result_t result;
+       gpgme_subkey_t subkey;
+       gpgme_signature_t sig;
+       gpgme_user_id_t uid;
+       gpgme_key_t key;
        
-       gpg->signature = sig = g_mime_signature_new ();
-       g_mime_signature_set_status (sig, status);
-       g_mime_signature_list_add (gpg->signatures, sig);
-       g_object_unref (sig);
+       /* get the signature verification results from GpgMe */
+       if (!(result = gpgme_op_verify_result (gpg->ctx)) || !result->signatures)
+               return verify ? g_mime_signature_list_new () : NULL;
        
-       /* get the key id of the signer */
-       info = next_token (info, FALSE, &sig->cert->keyid);
+       /* create a new signature list to return */
+       signatures = g_mime_signature_list_new ();
        
-       /* the rest of the string is the signer's name */
-       sig->cert->name = g_strdup (info);
-}
-
-static void
-gpg_ctx_parse_signer_info (struct _GpgCtx *gpg, char *status)
-{
-       GMimeSignature *sig;
-       char *inend;
-       
-       if (!strncmp (status, "SIG_ID ", 7)) {
-               /* not sure if this contains anything we care about... */
-       } else if (!strncmp (status, "GOODSIG ", 8)) {
-               gpg_ctx_add_signature (gpg, GMIME_SIGNATURE_STATUS_GOOD, status + 8);
-       } else if (!strncmp (status, "BADSIG ", 7)) {
-               gpg_ctx_add_signature (gpg, GMIME_SIGNATURE_STATUS_BAD, status + 7);
-       } else if (!strncmp (status, "EXPSIG ", 7)) {
-               gpg_ctx_add_signature (gpg, GMIME_SIGNATURE_STATUS_ERROR, status + 7);
-               gpg->signature->errors |= GMIME_SIGNATURE_ERROR_EXPSIG;
-       } else if (!strncmp (status, "EXPKEYSIG ", 10)) {
-               gpg_ctx_add_signature (gpg, GMIME_SIGNATURE_STATUS_ERROR, status + 10);
-               gpg->signature->errors |= GMIME_SIGNATURE_ERROR_EXPKEYSIG;
-       } else if (!strncmp (status, "REVKEYSIG ", 10)) {
-               gpg_ctx_add_signature (gpg, GMIME_SIGNATURE_STATUS_ERROR, status + 10);
-               gpg->signature->errors |= GMIME_SIGNATURE_ERROR_REVKEYSIG;
-       } else if (!strncmp (status, "ERRSIG ", 7)) {
-               /* Note: NO_PUBKEY often comes after an ERRSIG */
-               status += 7;
-               
-               if (!gpg->signatures)
-                       gpg->signatures = g_mime_signature_list_new ();
-               
-               gpg->signature = sig = g_mime_signature_new ();
-               g_mime_signature_set_status (sig, GMIME_SIGNATURE_STATUS_ERROR);
-               g_mime_signature_list_add (gpg->signatures, sig);
-               g_object_unref (sig);
-               
-               /* get the key id of the signer */
-               status = next_token (status, FALSE, &sig->cert->keyid);
-               
-               /* the second token is the public-key algorithm id */
-               sig->cert->pubkey_algo = strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       sig->cert->pubkey_algo = 0;
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the third token is the digest algorithm id */
-               sig->cert->digest_algo = strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       sig->cert->digest_algo = 0;
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the fourth token is the signature class */
-               /*sig->sig_class =*/ strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       /*signer->sig_class = 0;*/
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the fifth token is the signature expiration date (or 0 for never) */
-               sig->expires = strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       sig->expires = 0;
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the sixth token is the return code */
-               switch (strtol (status, NULL, 10)) {
-               case 4: sig->errors |= GMIME_SIGNATURE_ERROR_UNSUPP_ALGO; break;
-               case 9: sig->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY; break;
-               default: break;
-               }
-       } else if (!strncmp (status, "NO_PUBKEY ", 10)) {
-               /* the only token is the keyid, but we've already got it */
-               gpg->signature->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY;
-       } else if (!strncmp (status, "VALIDSIG ", 9)) {
-               sig = gpg->signature;
-               status += 9;
-               
-               /* the first token is the fingerprint */
-               status = next_token (status, FALSE, &sig->cert->fingerprint);
-               
-               /* the second token is the date the stream was signed YYYY-MM-DD */
-               status = next_token (status, FALSE, NULL);
-               
-               /* the third token is the signature creation date (or 0 for unknown?) */
-               sig->created = strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       sig->created = 0;
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the fourth token is the signature expiration date (or 0 for never) */
-               sig->expires = strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       sig->expires = 0;
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the fifth token is the signature version */
-               /*sig->sig_ver =*/ strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       /*signer->sig_ver = 0;*/
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the sixth token is a reserved numeric value (ignore for now) */
-               status = next_token (status, FALSE, NULL);
-               
-               /* the seventh token is the public-key algorithm id */
-               sig->cert->pubkey_algo = strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       sig->cert->pubkey_algo = 0;
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the eighth token is the digest algorithm id */
-               sig->cert->digest_algo = strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       sig->cert->digest_algo = 0;
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the nineth token is the signature class */
-               /*sig->sig_class =*/ strtoul (status, &inend, 10);
-               if (inend == status || *inend != ' ') {
-                       /*sig->sig_class = 0;*/
-                       return;
-               }
-               
-               status = inend + 1;
-               
-               /* the rest is the primary key fingerprint */
-       } else if (!strncmp (status, "TRUST_", 6)) {
-               status += 6;
-               
-               sig = gpg->signature;
-               if (!strncmp (status, "NEVER", 5)) {
-                       sig->cert->trust = GMIME_CERTIFICATE_TRUST_NEVER;
-               } else if (!strncmp (status, "MARGINAL", 8)) {
-                       sig->cert->trust = GMIME_CERTIFICATE_TRUST_MARGINAL;
-               } else if (!strncmp (status, "FULLY", 5)) {
-                       sig->cert->trust = GMIME_CERTIFICATE_TRUST_FULLY;
-               } else if (!strncmp (status, "ULTIMATE", 8)) {
-                       sig->cert->trust = GMIME_CERTIFICATE_TRUST_ULTIMATE;
-               } else if (!strncmp (status, "UNDEFINED", 9)) {
-                       sig->cert->trust = GMIME_CERTIFICATE_TRUST_UNDEFINED;
-               }
-       }
-}
-
-/* write the session_key to the secret file descriptor and close
-   it.  Returns 0 on success. */
-static int
-gpg_ctx_write_session_key (struct _GpgCtx *gpg, const char *session_key)
-{
-       size_t len = strlen (session_key);
-       ssize_t w, nwritten = 0;
+       sig = result->signatures;
        
-       do {
-               do {
-                       w = write (gpg->secret_fd, session_key + nwritten, len - nwritten);
-               } while (w == -1 && (errno == EINTR || errno == EAGAIN));
+       while (sig != NULL) {
+               signature = g_mime_signature_new ();
+               g_mime_signature_list_add (signatures, signature);
                
-               if (w > 0)
-                       nwritten += w;
-       } while (nwritten < len && w != -1);
-       
-       close (gpg->secret_fd);
-       gpg->secret_fd = -1;
-       
-       return (w == -1);
-}
-
-static int
-gpg_ctx_parse_status (struct _GpgCtx *gpg, GError **err)
-{
-       size_t nread, nwritten;
-       register char *inptr;
-       char *status, *tmp;
-       int len;
-       
- parse:
-       
-       g_clear_error (err);
-       
-       inptr = gpg->statusbuf;
-       while (inptr < gpg->statusptr && *inptr != '\n')
-               inptr++;
-       
-       if (*inptr != '\n') {
-               /* we don't have enough data buffered to parse this status line */
-               return 0;
-       }
-       
-       *inptr++ = '\0';
-       status = gpg->statusbuf;
-       
-       d(printf ("status: %s\n", status));
-       
-       if (strncmp (status, "[GNUPG:] ", 9) != 0) {
-               if (!gpg->utf8)
-                       tmp = g_locale_to_utf8 (status, -1, &nread, &nwritten, NULL);
+               if (sig->status != GPG_ERR_NO_ERROR)
+                       g_mime_signature_set_status (signature, GMIME_SIGNATURE_STATUS_ERROR);
                else
-                       tmp = status;
-               
-               g_set_error (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
-                            _("Unexpected GnuPG status message encountered:\n\n%s"),
-                            tmp);
-               
-               if (!gpg->utf8)
-                       g_free (tmp);
-               
-               return -1;
-       }
-       
-       status += 9;
-       
-       if (!strncmp (status, "USERID_HINT ", 12)) {
-               size_t nread, nwritten;
-               char *hint, *user;
-               
-               status += 12;
-               
-               status = next_token (status, FALSE, &hint);
-               if (!hint) {
-                       g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
-                                            _("Failed to parse gpg userid hint."));
-                       return -1;
-               }
-               
-               if (g_hash_table_lookup (gpg->userid_hint, hint)) {
-                       /* we already have this userid hint... */
-                       g_free (hint);
-                       goto recycle;
-               }
-               
-               if (gpg->utf8 || !(user = g_locale_to_utf8 (status, -1, &nread, &nwritten, NULL)))
-                       user = g_strdup (status);
-               
-               g_strstrip (user);
-               
-               g_hash_table_insert (gpg->userid_hint, hint, user);
-       } else if (!strncmp (status, "NEED_PASSPHRASE ", 16)) {
-               char *userid;
-               
-               status += 16;
-               
-               status = next_token (status, FALSE, &userid);
-               if (!userid) {
-                       g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
-                                            _("Failed to parse gpg passphrase request."));
-                       return -1;
-               }
-               
-               g_free (gpg->need_id);
-               gpg->need_id = userid;
-       } else if (!strncmp (status, "NEED_PASSPHRASE_PIN ", 20)) {
-               char *userid;
-               
-               status += 20;
-               
-               status = next_token (status, FALSE, &userid);
-               if (!userid) {
-                       g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
-                                            _("Failed to parse gpg passphrase request."));
-                       return -1;
-               }
-               
-               g_free (gpg->need_id);
-               gpg->need_id = userid;
-       } else if (!strncmp (status, "GET_HIDDEN ", 11)) {
-               GMimeStream *filtered_stream, *passwd;
-               GMimeCryptoContext *ctx;
-               GMimeFilter *filter;
-               const char *charset;
-               char *prompt = NULL;
-               const char *name;
-               gboolean ok;
-               
-               status += 11;
-               
-               ctx = (GMimeCryptoContext *) gpg->ctx;
-               if (!ctx->request_passwd) {
-                       /* can't ask for a passwd w/o a way to request it from the user... */
-                       g_set_error_literal (err, GMIME_ERROR, ECANCELED, _("Canceled."));
-                       return -1;
-               }
-               
-               if (!(name = g_hash_table_lookup (gpg->userid_hint, gpg->need_id)))
-                       name = gpg->userid;
-               
-               if (!strncmp (status, "passphrase.pin.ask", 18)) {
-                       prompt = g_strdup_printf (_("You need a PIN to unlock the key for your\n"
-                                                   "SmartCard: \"%s\""), name);
-               } else if (!strncmp (status, "passphrase.enter", 16)) {
-                       prompt = g_strdup_printf (_("You need a passphrase to unlock the key for\n"
-                                                   "user: \"%s\""), name);
-               } else {
-                       next_token (status, FALSE, &prompt);
-                       g_set_error (err, GMIME_ERROR, GMIME_ERROR_GENERAL,
-                                    _("Unexpected request from GnuPG for `%s'"), prompt);
-                       g_free (prompt);
-                       return -1;
-               }
-               
-               /* create a stream for the application to write the passwd to */
-               passwd = g_mime_stream_pipe_new (gpg->secret_fd);
-               g_mime_stream_pipe_set_owner ((GMimeStreamPipe *) passwd, FALSE);
-               
-               if (!gpg->utf8) {
-                       /* we'll need to transcode the UTF-8 password that the application
-                        * will write to our stream into the locale charset used by gpg */
-                       filtered_stream = g_mime_stream_filter_new (passwd);
-                       g_object_unref (passwd);
-                       
-                       charset = g_mime_locale_charset ();
-                       filter = g_mime_filter_charset_new ("UTF-8", charset);
-                       
-                       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered_stream, filter);
-                       g_object_unref (filter);
-                       
-                       passwd = filtered_stream;
-               }
-               
-               if ((ok = ctx->request_passwd (ctx, name, prompt, gpg->bad_passwds > 0, passwd, err))) {
-                       if (g_mime_stream_flush (passwd) == -1)
-                               ok = FALSE;
-               }
-               
-               g_object_unref (passwd);
-               g_free (prompt);
-               
-               if (!ok)
-                       return -1;
-       } else if (!strncmp (status, "GOOD_PASSPHRASE", 15)) {
-               gpg->bad_passwds = 0;
-       } else if (!strncmp (status, "BAD_PASSPHRASE", 14)) {
-               gpg->bad_passwds++;
-               
-               if (gpg->bad_passwds == 3) {
-                       g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_BAD_PASSWORD,
-                                            _("Failed to unlock secret key: 3 bad passphrases given."));
-                       return -1;
+                       g_mime_signature_set_status (signature, GMIME_SIGNATURE_STATUS_GOOD);
+               
+               g_mime_certificate_set_pubkey_algo (signature->cert, (GMimePubKeyAlgo) sig->pubkey_algo);
+               g_mime_certificate_set_digest_algo (signature->cert, (GMimeDigestAlgo) sig->hash_algo);
+               g_mime_certificate_set_fingerprint (signature->cert, sig->fpr);
+               g_mime_signature_set_expires (signature, sig->exp_timestamp);
+               g_mime_signature_set_created (signature, sig->timestamp);
+               
+               if (sig->exp_timestamp != 0 && sig->exp_timestamp <= time (NULL)) {
+                       /* signature expired, automatically results in a BAD signature */
+                       signature->errors |= GMIME_SIGNATURE_ERROR_EXPSIG;
+                       signature->status = GMIME_SIGNATURE_STATUS_BAD;
                }
-       } else if (!strncmp (status, "UNEXPECTED ", 11)) {
-               /* this is an error */
-               if (!gpg->utf8)
-                       tmp = g_locale_to_utf8 (status + 11, -1, &nread, &nwritten, NULL);
-               else
-                       tmp = status + 11;
-               
-               g_set_error (err, GMIME_ERROR, GMIME_ERROR_GENERAL,
-                            _("Unexpected response from GnuPG: %s"),
-                            tmp);
-               
-               if (!gpg->utf8)
-                       g_free (tmp);
-               
-               return -1;
-       } else if (!strncmp (status, "NODATA", 6)) {
-               /* this is an error */
-               const char *diagnostics;
                
-               diagnostics = gpg_ctx_get_diagnostics (gpg);
-               if (diagnostics && *diagnostics)
-                       g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_GENERAL, diagnostics);
-               else
-                       g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_GENERAL, _("No data provided"));
-               
-               return -1;
-       } else {
-               GMimeCertificate *cert;
-               char *inend;
-               
-               switch (gpg->mode) {
-               case GPG_CTX_MODE_SIGN:
-                       if (strncmp (status, "SIG_CREATED ", 12) != 0)
-                               break;
-                       
-                       status += 12;
-                       
-                       /* skip the next single-char token ("D" for detached) */
-                       status = next_token (status, FALSE, NULL);
+               if (gpgme_get_key (gpg->ctx, sig->fpr, &key, 0) == GPG_ERR_NO_ERROR && key) {
+                       /* get more signer info from their signing key */
+                       g_mime_certificate_set_trust (signature->cert, gpg_trust (key->owner_trust));
+                       g_mime_certificate_set_issuer_serial (signature->cert, key->issuer_serial);
+                       g_mime_certificate_set_issuer_name (signature->cert, key->issuer_name);
                        
-                       /* skip the public-key algorithm id token */
-                       status = next_token (status, FALSE, NULL);
-                       
-                       /* this token is the digest algorithm used */
-                       gpg->digest = strtoul (status, NULL, 10);
-                       break;
-               case GPG_CTX_MODE_VERIFY:
-                       gpg_ctx_parse_signer_info (gpg, status);
-                       break;
-               case GPG_CTX_MODE_SIGN_ENCRYPT:
-               case GPG_CTX_MODE_ENCRYPT:
-                       if (!strncmp (status, "BEGIN_ENCRYPTION", 16)) {
-                               /* nothing to do... but we know to expect data on stdout soon */
-                       } else if (!strncmp (status, "END_ENCRYPTION", 14)) {
-                               /* nothing to do, but we know the end is near? */
-                       } else if (!strncmp (status, "NO_RECP", 7)) {
-                               g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_NO_VALID_RECIPIENTS,
-                                                    _("Failed to encrypt: No valid recipients specified."));
-                               return -1;
-                       }
-                       break;
-               case GPG_CTX_MODE_DECRYPT:
-                       if (!strncmp (status, "BEGIN_DECRYPTION", 16)) {
-                               /* nothing to do... but we know to expect data on stdout soon */
-                       } else if (!strncmp (status, "DECRYPTION_INFO ", 16)) {
-                               /* new feature added in gnupg-2.1.x which gives mdc and cipher algorithms 
used */
-                               status += 16;
+                       /* get the keyid, name, and email address */
+                       uid = key->uids;
+                       while (uid) {
+                               if (uid->name && *uid->name)
+                                       g_mime_certificate_set_name (signature->cert, uid->name);
                                
-                               /* first token is the mdc algorithm (or 0 if not used) */
-                               gpg->digest = strtoul (status, &inend, 10);
-                               if (inend == status || *inend != ' ') {
-                                       gpg->digest = 0;
-                                       break;
-                               }
-                               
-                               status = inend + 1;
-                               
-                               /* second token is the cipher algorithm */
-                               gpg->cipher = strtoul (status, &inend, 10);
-                       } else if (!strncmp (status, "DECRYPTION_OKAY", 15)) {
-                               /* decryption succeeded */
-                               gpg->decrypt_okay = TRUE;
-                       } else if (!strncmp (status, "DECRYPTION_FAILED", 17)) {
-                               /* nothing to do... but we know gpg failed to decrypt :-( */
-                       } else if (!strncmp (status, "END_DECRYPTION", 14)) {
-                               /* nothing to do, but we know we're done */
-                       } else if (!strncmp (status, "ENC_TO ", 7)) {
-                               /* parse the recipient info */
-                               if (!gpg->encrypted_to)
-                                       gpg->encrypted_to = g_mime_certificate_list_new ();
-                               
-                               cert = g_mime_certificate_new ();
-                               g_mime_certificate_list_add (gpg->encrypted_to, cert);
+                               if (uid->email && *uid->email)
+                                       g_mime_certificate_set_email (signature->cert, uid->email);
                                
-                               status += 7;
+                               if (uid->uid && *uid->uid)
+                                       g_mime_certificate_set_key_id (signature->cert, uid->uid);
                                
-                               /* first token is the recipient's keyid */
-                               status = next_token (status, FALSE, &cert->keyid);
-                               
-                               /* second token is the recipient's pubkey algo */
-                               cert->pubkey_algo = strtoul (status, &inend, 10);
-                               if (inend == status || *inend != ' ') {
-                                       cert->pubkey_algo = 0;
-                                       g_object_unref (cert);
+                               if (signature->cert->name && signature->cert->email && signature->cert->keyid)
                                        break;
-                               }
                                
-                               g_object_unref (cert);
-                               status = inend + 1;
+                               uid = uid->next;
+                       }
+                       
+                       /* get the subkey used for signing */
+                       subkey = key->subkeys;
+                       while (subkey && !subkey->can_sign)
+                               subkey = subkey->next;
+                       
+                       if (subkey) {
+                               g_mime_certificate_set_created (signature->cert, subkey->timestamp);
+                               g_mime_certificate_set_expires (signature->cert, subkey->expires);
                                
-                               /* third token is a dummy value which is always '0' */
-                       } else if (!strncmp (status, "GOODMDC", 7)) {
-                               /* nothing to do... we'll grab the MDC used in DECRYPTION_INFO */
-                       } else if (!strncmp (status, "BADMDC", 6)) {
-                               /* nothing to do, this will only be sent after DECRYPTION_FAILED */
-                       } else if (!strncmp (status, "SESSION_KEY", 11)) {
-                               if (gpg->session_key) {
-                                       memset (gpg->session_key, 0, strlen (gpg->session_key));
-                                       g_free (gpg->session_key);
+                               if (subkey->revoked) {
+                                       /* signer's key has been revoked, automatic BAD status */
+                                       signature->errors |= GMIME_SIGNATURE_ERROR_REVKEYSIG;
+                                       signature->status = GMIME_SIGNATURE_STATUS_BAD;
                                }
-
-                               status += 11;
                                
-                               status = next_token (status, TRUE, &gpg->session_key);
+                               if (subkey->expired) {
+                                       /* signer's key has expired, automatic BAD status */
+                                       signature->errors |= GMIME_SIGNATURE_ERROR_EXPKEYSIG;
+                                       signature->status = GMIME_SIGNATURE_STATUS_BAD;
+                               }
                        } else {
-                               gpg_ctx_parse_signer_info (gpg, status);
+                               /* If we don't have the subkey used by the signer, then we can't
+                                * tell what the status is, so set to ERROR if it hasn't already
+                                * been designated as BAD. */
+                               if (signature->status != GMIME_SIGNATURE_STATUS_BAD)
+                                       signature->status = GMIME_SIGNATURE_STATUS_ERROR;
+                               signature->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY;
                        }
-                       break;
-               case GPG_CTX_MODE_IMPORT:
-                       /* no-op */
-                       break;
-               case GPG_CTX_MODE_EXPORT:
-                       /* no-op */
-                       break;
-               }
-       }
-       
- recycle:
-       
-       /* recycle our statusbuf by moving inptr to the beginning of statusbuf */
-       len = gpg->statusptr - inptr;
-       memmove (gpg->statusbuf, inptr, len);
-       
-       len = inptr - gpg->statusbuf;
-       gpg->statusleft += len;
-       gpg->statusptr -= len;
-       
-       /* if we have more data, try parsing the next line? */
-       if (gpg->statusptr > gpg->statusbuf)
-               goto parse;
-       
-       return 0;
-}
-
-#ifdef ALLOC_NEAREST_POW2
-static inline size_t
-nearest_pow (size_t num)
-{
-       size_t n;
-       
-       if (num == 0)
-               return 0;
-       
-       n = num - 1;
-#if defined (__GNUC__) && defined (__i386__)
-       __asm__("bsrl %1,%0\n\t"
-               "jnz 1f\n\t"
-               "movl $-1,%0\n"
-               "1:" : "=r" (n) : "rm" (n));
-       n = (1 << (n + 1));
-#else
-       n |= n >> 1;
-       n |= n >> 2;
-       n |= n >> 4;
-       n |= n >> 8;
-       n |= n >> 16;
-       n++;
-#endif
-       
-       return n;
-}
-
-#define next_alloc_size(n) nearest_pow (n)
-#else
-static inline size_t
-next_alloc_size (size_t n)
-{
-       return (n + 63) & ~63;
-}
-#endif
-
-#define status_backup(gpg, start, len) G_STMT_START {                     \
-       if (gpg->statusleft <= len) {                                     \
-               size_t slen, soff;                                        \
-                                                                         \
-               soff = gpg->statusptr - gpg->statusbuf;                   \
-               slen = next_alloc_size (soff + len + 1);                  \
-                                                                         \
-               gpg->statusbuf = g_realloc (gpg->statusbuf, slen);        \
-               gpg->statusptr = gpg->statusbuf + soff;                   \
-               gpg->statusleft = (slen - 1) - soff;                      \
-       }                                                                 \
-                                                                         \
-       memcpy (gpg->statusptr, start, len);                              \
-       gpg->statusptr += len;                                            \
-       gpg->statusleft -= len;                                           \
-} G_STMT_END
-
-enum {
-       GPG_STDIN_FD,
-       GPG_STDOUT_FD,
-       GPG_STDERR_FD,
-       GPG_STATUS_FD,
-       GPG_VERIFY_FD,
-       GPG_N_FDS
-};
-
-#ifndef HAVE_POLL
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#define POLLIN   (1 << 0)
-#define POLLPRI  (1 << 1)
-#define POLLOUT  (1 << 2)
-#define POLLERR  (1 << 3)
-#define POLLHUP  (1 << 4)
-#define POLLNVAL (1 << 5)
-
-#ifdef HAVE_SELECT
-static int
-poll (struct pollfd *pfds, nfds_t nfds, int timeout)
-{
-       fd_set rset, wset, xset;
-       struct timeval tv;
-       int maxfd = 0;
-       int ready;
-       nfds_t i;
-       
-       if (nfds == 0)
-               return 0;
-       
-       /* initialize our select() timeout */
-       tv.tv_sec = timeout / 1000;
-       tv.tv_usec = (timeout % 1000) * 1000;
-       
-       /* initialize our select() fd sets */
-       FD_ZERO (&rset);
-       FD_ZERO (&wset);
-       FD_ZERO (&xset);
-       
-       for (i = 0; i < nfds; i++) {
-               pfds[i].revents = 0;
-               if (pfds[i].fd < 0)
-                       continue;
-               
-               if (pfds[i].events & POLLIN)
-                       FD_SET (pfds[i].fd, &rset);
-               if (pfds[i].events & POLLOUT)
-                       FD_SET (pfds[i].fd, &wset);
-               if (pfds[i].events != 0)
-                       FD_SET (pfds[i].fd, &xset);
-               if (pfds[i].fd > maxfd)
-                       maxfd = pfds[i].fd;
-       }
-       
-       /* poll our fds... */
-       if ((ready = select (maxfd + 1, &rset, &wset, &xset, timeout != -1 ? &tv : NULL)) > 0) {
-               ready = 0;
-               
-               for (i = 0; i < nfds; i++) {
-                       if (pfds[i].fd < 0)
-                               continue;
                        
-                       if (FD_ISSET (pfds[i].fd, &rset))
-                               pfds[i].revents |= POLLIN;
-                       if (FD_ISSET (pfds[i].fd, &wset))
-                               pfds[i].revents |= POLLOUT;
-                       if (FD_ISSET (pfds[i].fd, &xset))
-                               pfds[i].revents |= POLLERR | POLLHUP;
-                       
-                       if (pfds[i].revents != 0)
-                               ready++;
-               }
-       }
-       
-       return ready;
-}
-#else
-static int
-poll (struct pollfd *pfds, nfds_t nfds, int timeout)
-{
-       errno = EIO;
-       return -1;
-}
-#endif /* HAVE_SELECT */
-#endif /* ! HAVE_POLL */
-
-static int
-gpg_ctx_op_step (struct _GpgCtx *gpg, GError **err)
-{
-       const char *diagnostics, *mode;
-       struct pollfd pfds[GPG_N_FDS];
-       int ready, save;
-       nfds_t n;
-       
-       for (n = 0; n < GPG_N_FDS; n++) {
-               pfds[n].events = 0;
-               pfds[n].fd = -1;
-       }
-       
-       if (!gpg->seen_eof1) {
-               pfds[GPG_STDOUT_FD].fd = gpg->stdout_fd;
-               pfds[GPG_STDOUT_FD].events = POLLIN;
-       }
-       
-       if (!gpg->seen_eof2) {
-               pfds[GPG_STDERR_FD].fd = gpg->stderr_fd;
-               pfds[GPG_STDERR_FD].events = POLLIN;
-       }
-       
-       if (!gpg->complete) {
-               pfds[GPG_STATUS_FD].fd = gpg->status_fd;
-               pfds[GPG_STATUS_FD].events = POLLIN;
-       }
-       
-       pfds[GPG_STDIN_FD].fd = gpg->stdin_fd;
-       pfds[GPG_STDIN_FD].events = POLLOUT;
-       
-       if (gpg->mode == GPG_CTX_MODE_VERIFY) {
-               pfds[GPG_VERIFY_FD].fd = gpg->secret_fd;
-               pfds[GPG_VERIFY_FD].events = POLLOUT;
-       }
-       
-       do {
-               for (n = 0; n < GPG_N_FDS; n++)
-                       pfds[n].revents = 0;
-               ready = poll (pfds, GPG_N_FDS, 10 * 1000);
-       } while (ready == -1 && errno == EINTR);
-       
-       if (ready == -1) {
-               d(printf ("poll() failed: %s\n", g_strerror (errno)));
-               goto exception;
-       } else if (ready == 0) {
-               /* timed out */
-               return 0;
-       }
-       
-       /* Test each and every file descriptor to see if it's 'ready',
-          and if so - do what we can with it and then drop through to
-          the next file descriptor and so on until we've done what we
-          can to all of them. If one fails along the way, return
-          -1. */
-       
-       if (pfds[GPG_STATUS_FD].revents & (POLLIN | POLLHUP)) {
-               /* read the status message and decide what to do... */
-               char buffer[4096];
-               ssize_t nread;
-               
-               d(printf ("reading gpg's status-fd...\n"));
-               
-               do {
-                       nread = read (gpg->status_fd, buffer, sizeof (buffer));
-               } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
-               
-               if (nread == -1)
-                       goto exception;
-               
-               if (nread > 0) {
-                       status_backup (gpg, buffer, (size_t) nread);
-                       if (gpg_ctx_parse_status (gpg, err) == -1)
-                               return -1;
-               } else {
-                       gpg->complete = TRUE;
-               }
-       }
-       
-       if ((pfds[GPG_STDOUT_FD].revents & (POLLIN | POLLHUP)) && gpg->ostream) {
-               char buffer[4096];
-               ssize_t nread;
-               
-               d(printf ("reading gpg's stdout...\n"));
-               
-               do {
-                       nread = read (gpg->stdout_fd, buffer, sizeof (buffer));
-               } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
-               
-               if (nread == -1)
-                       goto exception;
-               
-               if (nread > 0) {
-                       if (g_mime_stream_write (gpg->ostream, buffer, (size_t) nread) == -1)
-                               goto exception;
+                       gpgme_key_unref (key);
                } else {
-                       gpg->seen_eof1 = TRUE;
+                       /* If we don't have the signer's public key, then we can't tell what
+                        * the status is, so set it to ERROR if it hasn't already been
+                        * designated as BAD. */
+                       g_mime_certificate_set_trust (signature->cert, GMIME_CERTIFICATE_TRUST_UNDEFINED);
+                       if (signature->status != GMIME_SIGNATURE_STATUS_BAD)
+                               signature->status = GMIME_SIGNATURE_STATUS_ERROR;
+                       signature->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY;
                }
-       }
-       
-       if (pfds[GPG_STDERR_FD].revents & (POLLIN | POLLHUP)) {
-               char buffer[4096];
-               ssize_t nread;
-               
-               d(printf ("reading gpg's stderr...\n"));
                
-               do {
-                       nread = read (gpg->stderr_fd, buffer, sizeof (buffer));
-               } while (nread == -1 && (errno == EINTR || errno == EAGAIN));
-               
-               if (nread == -1)
-                       goto exception;
-               
-               if (nread > 0) {
-                       g_mime_stream_write (gpg->diagnostics, buffer, nread);
-               } else {
-                       gpg->seen_eof2 = TRUE;
-               }
+               sig = sig->next;
        }
        
-       if ((pfds[GPG_VERIFY_FD].revents & (POLLOUT | POLLHUP))) {
-               char buffer[4096];
-               ssize_t nread;
-               
-               d(printf ("streaming digital signature to gpg...\n"));
-               
-               /* write our signature stream to gpg's special fd */
-               nread = g_mime_stream_read (gpg->sigstream, buffer, sizeof (buffer));
-               if (nread > 0) {
-                       ssize_t w, nwritten = 0;
-                       
-                       do {
-                               do {
-                                       w = write (gpg->secret_fd, buffer + nwritten, nread - nwritten);
-                               } while (w == -1 && (errno == EINTR || errno == EAGAIN));
-                               
-                               if (w > 0)
-                                       nwritten += w;
-                       } while (nwritten < nread && w != -1);
-                       
-                       if (w == -1)
-                               goto exception;
-               }
-               
-               if (g_mime_stream_eos (gpg->sigstream)) {
-                       close (gpg->secret_fd);
-                       gpg->secret_fd = -1;
-               }
-       }
-       
-       if ((pfds[GPG_STDIN_FD].revents & (POLLOUT | POLLHUP)) && gpg->istream) {
-               char buffer[4096];
-               ssize_t nread;
-               
-               d(printf ("writing to gpg's stdin...\n"));
-               
-               /* write our stream to gpg's stdin */
-               nread = g_mime_stream_read (gpg->istream, buffer, sizeof (buffer));
-               if (nread > 0) {
-                       ssize_t w, nwritten = 0;
-                       
-                       do {
-                               do {
-                                       w = write (gpg->stdin_fd, buffer + nwritten, nread - nwritten);
-                               } while (w == -1 && (errno == EINTR || errno == EAGAIN));
-                               
-                               if (w > 0)
-                                       nwritten += w;
-                       } while (nwritten < nread && w != -1);
-                       
-                       if (w == -1)
-                               goto exception;
-               }
-               
-               if (g_mime_stream_eos (gpg->istream)) {
-                       close (gpg->stdin_fd);
-                       gpg->stdin_fd = -1;
-               }
-       }
-       
-       return 0;
-       
- exception:
-       
-       switch (gpg->mode) {
-       case GPG_CTX_MODE_SIGN:
-               mode = "sign";
-               break;
-       case GPG_CTX_MODE_VERIFY:
-               mode = "verify";
-               break;
-       case GPG_CTX_MODE_SIGN_ENCRYPT:
-       case GPG_CTX_MODE_ENCRYPT:
-               mode = "encrypt";
-               break;
-       case GPG_CTX_MODE_DECRYPT:
-               mode = "decrypt";
-               break;
-       case GPG_CTX_MODE_IMPORT:
-               mode = "import keys";
-               break;
-       case GPG_CTX_MODE_EXPORT:
-               mode = "export keys";
-               break;
-       default:
-               g_assert_not_reached ();
-               mode = NULL;
-               break;
-       }
-       
-       save = errno;
-       diagnostics = gpg_ctx_get_diagnostics (gpg);
-       errno = save;
-       
-       if (diagnostics && *diagnostics) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to %s via GnuPG: %s\n\n%s"),
-                            mode, g_strerror (errno),
-                            diagnostics);
-       } else {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to %s via GnuPG: %s\n"),
-                            mode, g_strerror (errno));
-       }
-       
-       return -1;
-}
-
-static gboolean
-gpg_ctx_op_complete (struct _GpgCtx *gpg)
-{
-       return gpg->complete && gpg->seen_eof1 && gpg->seen_eof2;
-}
-
-#if 0
-static gboolean
-gpg_ctx_op_exited (struct _GpgCtx *gpg)
-{
-       int status;
-       
-       if (waitpid (gpg->pid, &status, WNOHANG) == gpg->pid) {
-               gpg->exit_status = status;
-               gpg->exited = TRUE;
-               return TRUE;
-       }
-       
-       return FALSE;
-}
-#endif
-
-static void
-gpg_ctx_op_cancel (struct _GpgCtx *gpg)
-{
-       int status;
-       
-       if (gpg->exited)
-               return;
-       
-       kill (gpg->pid, SIGTERM);
-       sleep (1);
-       if (waitpid (gpg->pid, &status, WNOHANG) == 0) {
-               /* no more mr nice guy... */
-               kill (gpg->pid, SIGKILL);
-               sleep (1);
-               waitpid (gpg->pid, &status, WNOHANG);
-       }
-}
-
-static int
-gpg_ctx_op_wait (struct _GpgCtx *gpg)
-{
-       int errnosave, status;
-       sigset_t mask, omask;
-       pid_t retval;
-       
-       if (!gpg->exited) {
-               sigemptyset (&mask);
-               sigaddset (&mask, SIGALRM);
-               sigprocmask (SIG_BLOCK, &mask, &omask);
-               
-               alarm (1);
-               retval = waitpid (gpg->pid, &status, 0);
-               errnosave = errno;
-               alarm (0);
-               
-               sigprocmask (SIG_SETMASK, &omask, NULL);
-               errno = errnosave;
-               
-               if (retval == (pid_t) -1 && errno == EINTR) {
-                       /* gpg is hanging... */
-                       kill (gpg->pid, SIGTERM);
-                       sleep (1);
-                       
-                       retval = waitpid (gpg->pid, &status, WNOHANG);
-                       if (retval == (pid_t) 0) {
-                               /* still hanging... */
-                               kill (gpg->pid, SIGKILL);
-                               sleep (1);
-                               retval = waitpid (gpg->pid, &status, WNOHANG);
-                       }
-               }
-       } else {
-               status = gpg->exit_status;
-               retval = gpg->pid;
-       }
-       
-       if (retval != (pid_t) -1 && WIFEXITED (status))
-               return WEXITSTATUS (status);
-       else
-               return -1;
+       return signatures;
 }
 #endif /* ENABLE_CRYPTO */
 
-static int
-gpg_sign (GMimeCryptoContext *context, const char *userid, GMimeDigestAlgo digest,
-         GMimeStream *istream, GMimeStream *ostream, GError **err)
-{
-#ifdef ENABLE_CRYPTO
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
-       struct _GpgCtx *gpg;
-       
-       gpg = gpg_ctx_new (ctx);
-       gpg_ctx_set_mode (gpg, GPG_CTX_MODE_SIGN);
-       gpg_ctx_set_use_agent (gpg, ctx->use_agent);
-       gpg_ctx_set_digest (gpg, digest);
-       gpg_ctx_set_armor (gpg, TRUE);
-       gpg_ctx_set_userid (gpg, userid);
-       gpg_ctx_set_istream (gpg, istream);
-       gpg_ctx_set_ostream (gpg, ostream);
-       
-       if (gpg_ctx_op_start (gpg, ctx->path) == -1) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to execute gpg: %s"),
-                            errno ? g_strerror (errno) : _("Unknown"));
-               gpg_ctx_free (gpg);
-               
-               return -1;
-       }
-       
-       while (!gpg_ctx_op_complete (gpg)) {
-               if (gpg_ctx_op_step (gpg, err) == -1) {
-                       gpg_ctx_op_cancel (gpg);
-                       gpg_ctx_free (gpg);
-                       
-                       return -1;
-               }
-       }
-       
-       if (gpg_ctx_op_wait (gpg) != 0) {
-               const char *diagnostics;
-               int save;
-               
-               save = errno;
-               diagnostics = gpg_ctx_get_diagnostics (gpg);
-               errno = save;
-               
-               g_set_error_literal (err, GMIME_ERROR, errno, diagnostics);
-               gpg_ctx_free (gpg);
-               
-               return -1;
-       }
-       
-       /* save the digest used */
-       digest = gpg->digest;
-       
-       gpg_ctx_free (gpg);
-       
-       return digest;
-#else
-       g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("PGP support is not enabled in this 
build"));
-       
-       return -1;
-#endif /* ENABLE_CRYPTO */
-}
-
-
 static GMimeSignatureList *
 gpg_verify (GMimeCryptoContext *context, GMimeDigestAlgo digest,
            GMimeStream *istream, GMimeStream *sigstream,
            GError **err)
 {
 #ifdef ENABLE_CRYPTO
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
-       GMimeSignatureList *signatures;
-       struct _GpgCtx *gpg;
-       
-       gpg = gpg_ctx_new (ctx);
-       gpg_ctx_set_mode (gpg, GPG_CTX_MODE_VERIFY);
-       gpg_ctx_set_sigstream (gpg, sigstream);
-       gpg_ctx_set_istream (gpg, istream);
-       gpg_ctx_set_digest (gpg, digest);
-       
-       if (gpg_ctx_op_start (gpg, ctx->path) == -1) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to execute gpg: %s"),
-                            errno ? g_strerror (errno) : _("Unknown"));
-               gpg_ctx_free (gpg);
-               
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
+       gpgme_data_t message, signature;
+       gpgme_error_t error;
+       
+       if ((error = gpgme_data_new_from_cbs (&message, &gpg_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
                return NULL;
        }
        
-       while (!gpg_ctx_op_complete (gpg)) {
-               if (gpg_ctx_op_step (gpg, err) == -1) {
-                       gpg_ctx_op_cancel (gpg);
-                       gpg_ctx_free (gpg);
+       /* if @sigstream is non-NULL, then it is a detached signature */
+       if (sigstream != NULL) {
+               if ((error = gpgme_data_new_from_cbs (&signature, &gpg_stream_funcs, sigstream)) != 
GPG_ERR_NO_ERROR) {
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open signature stream"));
+                       gpgme_data_release (message);
                        return NULL;
                }
+       } else {
+               signature = NULL;
        }
        
-       /* Only set the GError if we got no signature information from gpg */
-       if (gpg_ctx_op_wait (gpg) != 0 && !gpg->signatures) {
-               const char *diagnostics;
-               int save;
-               
-               save = errno;
-               diagnostics = gpg_ctx_get_diagnostics (gpg);
-               errno = save;
-               
-               g_set_error_literal (err, GMIME_ERROR, errno, diagnostics);
-               gpg_ctx_free (gpg);
-               
+       if ((error = gpgme_op_verify (gpg->ctx, signature, message, NULL)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not verify gpg signature"));
+               if (signature)
+                       gpgme_data_release (signature);
+               gpgme_data_release (message);
                return NULL;
        }
        
-       signatures = gpg->signatures;
-       gpg->signatures = NULL;
-       gpg_ctx_free (gpg);
+       if (signature)
+               gpgme_data_release (signature);
        
-       return signatures;
+       if (message)
+               gpgme_data_release (message);
+       
+       /* get/return the gpg signatures */
+       return gpg_get_signatures (gpg, TRUE);
 #else
        g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("PGP support is not enabled in this 
build"));
        
@@ -2052,6 +693,20 @@ gpg_verify (GMimeCryptoContext *context, GMimeDigestAlgo digest,
 #endif /* ENABLE_CRYPTO */
 }
 
+#ifdef ENABLE_CRYPTO
+static void
+key_list_free (gpgme_key_t *keys)
+{
+       gpgme_key_t *key = keys;
+       
+       while (*key != NULL) {
+               gpgme_key_unref (*key);
+               key++;
+       }
+       
+       g_free (keys);
+}
+#endif /* ENABLE_CRYPTO */
 
 static int
 gpg_encrypt (GMimeCryptoContext *context, gboolean sign, const char *userid,
@@ -2059,61 +714,53 @@ gpg_encrypt (GMimeCryptoContext *context, gboolean sign, const char *userid,
             GMimeStream *ostream, GError **err)
 {
 #ifdef ENABLE_CRYPTO
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
-       struct _GpgCtx *gpg;
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
+       gpgme_data_t input, output;
+       gpgme_error_t error;
+       gpgme_key_t *rcpts;
+       gpgme_key_t key;
        guint i;
        
-       gpg = gpg_ctx_new (ctx);
        if (sign) {
-               gpg_ctx_set_mode (gpg, GPG_CTX_MODE_SIGN_ENCRYPT);
-               gpg_ctx_set_use_agent (gpg, ctx->use_agent);
-       } else {
-               gpg_ctx_set_mode (gpg, GPG_CTX_MODE_ENCRYPT);
-       }
-       
-       gpg_ctx_set_always_trust (gpg, ctx->always_trust);
-       gpg_ctx_set_digest (gpg, digest);
-       gpg_ctx_set_armor (gpg, TRUE);
-       gpg_ctx_set_userid (gpg, userid);
-       gpg_ctx_set_istream (gpg, istream);
-       gpg_ctx_set_ostream (gpg, ostream);
-       
-       for (i = 0; i < recipients->len; i++)
-               gpg_ctx_add_recipient (gpg, recipients->pdata[i]);
-       
-       if (gpg_ctx_op_start (gpg, ctx->path) == -1) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to execute gpg: %s"),
-                            errno ? g_strerror (errno) : _("Unknown"));
-               gpg_ctx_free (gpg);
-               
+               g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED,
+                            _("Cannot sign and encrypt a stream at the same time using gpg"));
                return -1;
        }
        
-       while (!gpg_ctx_op_complete (gpg)) {
-               if (gpg_ctx_op_step (gpg, err) == -1) {
-                       gpg_ctx_op_cancel (gpg);
-                       gpg_ctx_free (gpg);
-                       
+       /* create an array of recipient keys for GpgMe */
+       rcpts = g_new0 (gpgme_key_t, recipients->len + 1);
+       for (i = 0; i < recipients->len; i++) {
+               if (!(key = gpg_get_key_by_name (gpg, recipients->pdata[i], FALSE, err))) {
+                       key_list_free (rcpts);
                        return -1;
                }
+               
+               rcpts[i] = key;
        }
        
-       if (gpg_ctx_op_wait (gpg) != 0) {
-               const char *diagnostics;
-               int save;
-               
-               save = errno;
-               diagnostics = gpg_ctx_get_diagnostics (gpg);
-               errno = save;
-               
-               g_set_error_literal (err, GMIME_ERROR, errno, diagnostics);
-               gpg_ctx_free (gpg);
-               
+       if ((error = gpgme_data_new_from_cbs (&input, &gpg_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
+               key_list_free (rcpts);
+               return -1;
+       }
+       
+       if ((error = gpgme_data_new_from_cbs (&output, &gpg_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
+               gpgme_data_release (input);
+               key_list_free (rcpts);
                return -1;
        }
        
-       gpg_ctx_free (gpg);
+       /* encrypt the input stream */
+       error = gpgme_op_encrypt (gpg->ctx, rcpts, gpg->encrypt_flags, input, output);
+       gpgme_data_release (output);
+       gpgme_data_release (input);
+       key_list_free (rcpts);
+       
+       if (error != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Encryption failed"));
+               return -1;
+       }
        
        return 0;
 #else
@@ -2123,6 +770,36 @@ gpg_encrypt (GMimeCryptoContext *context, gboolean sign, const char *userid,
 #endif /* ENABLE_CRYPTO */
 }
 
+#ifdef ENABLE_CRYPTO
+static GMimeDecryptResult *
+gpg_get_decrypt_result (GMimeGpgContext *gpg)
+{
+       GMimeDecryptResult *result;
+       gpgme_decrypt_result_t res;
+       gpgme_recipient_t recipient;
+       GMimeCertificate *cert;
+       
+       result = g_mime_decrypt_result_new ();
+       result->recipients = g_mime_certificate_list_new ();
+       result->signatures = gpg_get_signatures (gpg, FALSE);
+       
+       if (!(res = gpgme_op_decrypt_result (gpg->ctx)) || !res->recipients)
+               return result;
+       
+       recipient = res->recipients;
+       while (recipient != NULL) {
+               cert = g_mime_certificate_new ();
+               g_mime_certificate_list_add (result->recipients, cert);
+               
+               g_mime_certificate_set_pubkey_algo (cert, (GMimePubKeyAlgo) recipient->pubkey_algo);
+               g_mime_certificate_set_key_id (cert, recipient->keyid);
+               
+               recipient = recipient->next;
+       }
+       
+       return result;
+}
+#endif /* ENABLE_CRYPTO */
 
 static GMimeDecryptResult *
 gpg_decrypt (GMimeCryptoContext *context, GMimeStream *istream,
@@ -2137,72 +814,35 @@ gpg_decrypt_session (GMimeCryptoContext *context, const char *session_key,
                     GError **err)
 {
 #ifdef ENABLE_CRYPTO
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
        GMimeDecryptResult *result;
-       const char *diagnostics;
-       struct _GpgCtx *gpg;
-       int save;
-       
-       gpg = gpg_ctx_new (ctx);
-       gpg_ctx_set_mode (gpg, GPG_CTX_MODE_DECRYPT);
-       gpg_ctx_set_use_agent (gpg, ctx->use_agent);
-       gpg_ctx_set_istream (gpg, istream);
-       gpg_ctx_set_ostream (gpg, ostream);
-       
-       if (session_key)
-               gpg->override_session_key = TRUE;
-       
-       if (gpg_ctx_op_start (gpg, ctx->path) == -1) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to execute gpg: %s"),
-                            errno ? g_strerror (errno) : _("Unknown"));
-               gpg_ctx_free (gpg);
-               
-               return NULL;
-       }
+       gpgme_decrypt_result_t res;
+       gpgme_data_t input, output;
+       gpgme_error_t error;
        
-       if (session_key && gpg_ctx_write_session_key (gpg, session_key)) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to pass session key to gpg: %s"),
-                            errno ? g_strerror (errno) : _("Unknown"));
-               gpg_ctx_free (gpg);
-               
+       if ((error = gpgme_data_new_from_cbs (&input, &gpg_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
                return NULL;
        }
        
-       while (!gpg_ctx_op_complete (gpg)) {
-               if (gpg_ctx_op_step (gpg, err) == -1) {
-                       gpg_ctx_op_cancel (gpg);
-                       gpg_ctx_free (gpg);
-                       
-                       return NULL;
-               }
+       if ((error = gpgme_data_new_from_cbs (&output, &gpg_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
+               gpgme_data_release (input);
+               return NULL;
        }
        
-       if (gpg_ctx_op_wait (gpg) != 0 && !gpg->decrypt_okay) {
-               save = errno;
-               diagnostics = gpg_ctx_get_diagnostics (gpg);
-               errno = save;
-               
-               g_set_error_literal (err, GMIME_ERROR, errno, diagnostics);
-               gpg_ctx_free (gpg);
-               
+       /* decrypt the input stream */
+       if ((error = gpgme_op_decrypt_verify (gpg->ctx, input, output)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Decryption failed"));
+               gpgme_data_release (output);
+               gpgme_data_release (input);
                return NULL;
        }
        
-       result = g_mime_decrypt_result_new ();
-       result->recipients = gpg->encrypted_to;
-       result->signatures = gpg->signatures;
-       result->session_key = gpg->session_key;
-       result->cipher = gpg->cipher;
-       result->mdc = gpg->digest;
-       gpg->encrypted_to = NULL;
-       gpg->signatures = NULL;
-       gpg->session_key = NULL;
-       
-       gpg_ctx_free (gpg);
+       gpgme_data_release (output);
+       gpgme_data_release (input);
        
-       return result;
+       return gpg_get_decrypt_result (gpg);
 #else
        g_set_error (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("PGP support is not enabled in this 
build"));
        
@@ -2214,46 +854,24 @@ static int
 gpg_import_keys (GMimeCryptoContext *context, GMimeStream *istream, GError **err)
 {
 #ifdef ENABLE_CRYPTO
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
-       struct _GpgCtx *gpg;
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
+       gpgme_data_t keydata;
+       gpgme_error_t error;
        
-       gpg = gpg_ctx_new (ctx);
-       gpg_ctx_set_mode (gpg, GPG_CTX_MODE_IMPORT);
-       gpg_ctx_set_istream (gpg, istream);
-       
-       if (gpg_ctx_op_start (gpg, ctx->path) == -1) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to execute gpg: %s"),
-                            errno ? g_strerror (errno) : _("Unknown"));
-               gpg_ctx_free (gpg);
-               
+       if ((error = gpgme_data_new_from_cbs (&keydata, &gpg_stream_funcs, istream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open input stream"));
                return -1;
        }
        
-       while (!gpg_ctx_op_complete (gpg)) {
-               if (gpg_ctx_op_step (gpg, err) == -1) {
-                       gpg_ctx_op_cancel (gpg);
-                       gpg_ctx_free (gpg);
-                       
-                       return -1;
-               }
-       }
-       
-       if (gpg_ctx_op_wait (gpg) != 0) {
-               const char *diagnostics;
-               int save;
-               
-               save = errno;
-               diagnostics = gpg_ctx_get_diagnostics (gpg);
-               errno = save;
-               
-               g_set_error_literal (err, GMIME_ERROR, errno, diagnostics);
-               gpg_ctx_free (gpg);
-               
+       /* import the key(s) */
+       if ((error = gpgme_op_import (gpg->ctx, keydata)) != GPG_ERR_NO_ERROR) {
+               //printf ("import error (%d): %s\n", error & GPG_ERR_CODE_MASK, gpg_strerror (error));
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not import key data"));
+               gpgme_data_release (keydata);
                return -1;
        }
        
-       gpg_ctx_free (gpg);
+       gpgme_data_release (keydata);
        
        return 0;
 #else
@@ -2267,52 +885,26 @@ static int
 gpg_export_keys (GMimeCryptoContext *context, GPtrArray *keys, GMimeStream *ostream, GError **err)
 {
 #ifdef ENABLE_CRYPTO
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
-       struct _GpgCtx *gpg;
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
+       gpgme_data_t keydata;
+       gpgme_error_t error;
        guint i;
        
-       gpg = gpg_ctx_new (ctx);
-       gpg_ctx_set_mode (gpg, GPG_CTX_MODE_EXPORT);
-       gpg_ctx_set_armor (gpg, TRUE);
-       gpg_ctx_set_ostream (gpg, ostream);
-       
-       for (i = 0; i < keys->len; i++) {
-               gpg_ctx_add_recipient (gpg, keys->pdata[i]);
-       }
-       
-       if (gpg_ctx_op_start (gpg, ctx->path) == -1) {
-               g_set_error (err, GMIME_ERROR, errno,
-                            _("Failed to execute gpg: %s"),
-                            errno ? g_strerror (errno) : _("Unknown"));
-               gpg_ctx_free (gpg);
-               
+       if ((error = gpgme_data_new_from_cbs (&keydata, &gpg_stream_funcs, ostream)) != GPG_ERR_NO_ERROR) {
+               g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not open output stream"));
                return -1;
        }
        
-       while (!gpg_ctx_op_complete (gpg)) {
-               if (gpg_ctx_op_step (gpg, err) == -1) {
-                       gpg_ctx_op_cancel (gpg);
-                       gpg_ctx_free (gpg);
-                       
+       /* export the key(s) */
+       for (i = 0; i < keys->len; i++) {
+               if ((error = gpgme_op_export (gpg->ctx, keys->pdata[i], 0, keydata)) != GPG_ERR_NO_ERROR) {
+                       g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not export key data"));
+                       gpgme_data_release (keydata);
                        return -1;
                }
        }
        
-       if (gpg_ctx_op_wait (gpg) != 0) {
-               const char *diagnostics;
-               int save;
-               
-               save = errno;
-               diagnostics = gpg_ctx_get_diagnostics (gpg);
-               errno = save;
-               
-               g_set_error_literal (err, GMIME_ERROR, errno, diagnostics);
-               gpg_ctx_free (gpg);
-               
-               return -1;
-       }
-       
-       gpg_ctx_free (gpg);
+       gpgme_data_release (keydata);
        
        return 0;
 #else
@@ -2327,7 +919,8 @@ gpg_get_retrieve_session_key (GMimeCryptoContext *context)
 {
        GMimeGpgContext *ctx = (GMimeGpgContext *) context;
        
-       return ctx->retrieve_session_key;
+       //return ctx->retrieve_session_key;
+       return FALSE;
 }
 
 
@@ -2336,7 +929,7 @@ gpg_set_retrieve_session_key (GMimeCryptoContext *context, gboolean retrieve_ses
 {
        GMimeGpgContext *ctx = (GMimeGpgContext *) context;
        
-       ctx->retrieve_session_key = retrieve_session_key;
+       //ctx->retrieve_session_key = retrieve_session_key;
        
        return 0;
 }
@@ -2344,94 +937,59 @@ gpg_set_retrieve_session_key (GMimeCryptoContext *context, gboolean retrieve_ses
 static gboolean
 gpg_get_always_trust (GMimeCryptoContext *context)
 {
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
+#ifdef ENABLE_CRYPTO
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
        
-       return ctx->always_trust;
+       return (gpg->encrypt_flags & GPGME_ENCRYPT_ALWAYS_TRUST) != 0;
+#else
+       return FALSE;
+#endif /* ENABLE_CRYPTO */
 }
 
 static void
 gpg_set_always_trust (GMimeCryptoContext *context, gboolean always_trust)
 {
-       GMimeGpgContext *ctx = (GMimeGpgContext *) context;
+#ifdef ENABLE_CRYPTO
+       GMimeGpgContext *gpg = (GMimeGpgContext *) context;
        
-       ctx->always_trust = always_trust;
+       if (always_trust)
+               gpg->encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
+       else
+               gpg->encrypt_flags &= ~GPGME_ENCRYPT_ALWAYS_TRUST;
+#endif /* ENABLE_CRYPTO */
 }
 
 
-int
-_g_mime_get_gpg_version (const char *path)
-{
-       const char vheader[] = "gpg (GnuPG) ";
-       int v, n = 0, version = 0;
-       const char *inptr;
-       char buffer[128];
-       char *command;
-       FILE *gpg;
-       
-       g_return_val_if_fail (path != NULL, -1);
-       
-       command = g_strdup_printf ("%s --version", path);
-       gpg = popen (command, "r");
-       g_free (command);
-       
-       if (gpg == NULL)
-               return -1;
-       
-       inptr = fgets (buffer, 128, gpg);
-       pclose (gpg);
-       
-       if (strncmp (inptr, vheader, sizeof (vheader) - 1) != 0)
-               return -1;
-       
-       inptr += sizeof (vheader) - 1;
-       while (*inptr >= '0' && *inptr <= '9' && n < 4) {
-               v = 0;
-               
-               while (*inptr >= '0' && *inptr <= '9' && (v < 25 || (v == 25 && *inptr < '6'))) {
-                       v = (v * 10) + (*inptr - '0');
-                       inptr++;
-               }
-               
-               version = (version << 8) + v;
-               n++;
-               
-               if (*inptr != '.')
-                       break;
-               
-               inptr++;
-       }
-       
-       if (n == 0)
-               return -1;
-       
-       if (n < 4)
-               version = version << ((4 - n) * 8);
-       
-       return version;
-}
-
 /**
  * g_mime_gpg_context_new:
  * @request_passwd: a #GMimePasswordRequestFunc
- * @path: path to gpg binary or %NULL for the default
  *
  * Creates a new gpg crypto context object.
  *
  * Returns: (transfer full): a new gpg crypto context object.
  **/
 GMimeCryptoContext *
-g_mime_gpg_context_new (GMimePasswordRequestFunc request_passwd, const char *path)
+g_mime_gpg_context_new (GMimePasswordRequestFunc request_passwd)
 {
 #ifdef ENABLE_CRYPTO
        GMimeCryptoContext *crypto;
-       GMimeGpgContext *ctx;
+       GMimeGpgContext *gpg;
+       gpgme_ctx_t ctx;
+       
+       /* make sure GpgMe supports the OpenPGP protocols */
+       if (gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
+               return NULL;
        
-       ctx = g_object_newv (GMIME_TYPE_GPG_CONTEXT, 0, NULL);
-       ctx->path = g_strdup (path ? path : "gpg");
+       /* create the GpgMe context */
+       if (gpgme_new (&ctx) != GPG_ERR_NO_ERROR)
+               return NULL;
        
-       ctx->version = _g_mime_get_gpg_version (ctx->path);
+       gpg = g_object_newv (GMIME_TYPE_GPG_CONTEXT, 0, NULL);
+       gpgme_set_passphrase_cb (ctx, gpg_passphrase_cb, gpg);
+       gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
+       gpg->ctx = ctx;
        
-       crypto = (GMimeCryptoContext *) ctx;
+       crypto = (GMimeCryptoContext *) gpg;
        crypto->request_passwd = request_passwd;
        
        return crypto;
@@ -2475,39 +1033,3 @@ g_mime_gpg_context_set_auto_key_retrieve (GMimeGpgContext *ctx, gboolean auto_ke
        
        ctx->auto_key_retrieve = auto_key_retrieve;
 }
-
-
-/**
- * g_mime_gpg_context_get_use_agent:
- * @ctx: a #GMimeGpgContext
- *
- * Gets whether or not gpg should attempt to use the gpg-agent when
- * requesting credentials.
- *
- * Returns: %TRUE if the gpg-agent should be used when requesting
- * credentials or %FALSE otherwise.
- **/
-gboolean
-g_mime_gpg_context_get_use_agent (GMimeGpgContext *ctx)
-{
-       g_return_val_if_fail (GMIME_IS_GPG_CONTEXT (ctx), FALSE);
-       
-       return ctx->use_agent;
-}
-
-
-/**
- * g_mime_gpg_context_set_use_agent:
- * @ctx: a #GMimeGpgContext
- * @use_agent: use agent flag
- *
- * Sets whether or not gpg should attempt to use the gpg-agent when
- * requesting credentials.
- **/
-void
-g_mime_gpg_context_set_use_agent (GMimeGpgContext *ctx, gboolean use_agent)
-{
-       g_return_if_fail (GMIME_IS_GPG_CONTEXT (ctx));
-       
-       ctx->use_agent = use_agent;
-}
diff --git a/gmime/gmime-gpg-context.h b/gmime/gmime-gpg-context.h
index 9ccc076..dae61ab 100644
--- a/gmime/gmime-gpg-context.h
+++ b/gmime/gmime-gpg-context.h
@@ -40,14 +40,11 @@ typedef struct _GMimeGpgContextClass GMimeGpgContextClass;
 GType g_mime_gpg_context_get_type (void);
 
 
-GMimeCryptoContext *g_mime_gpg_context_new (GMimePasswordRequestFunc request_passwd, const char *path);
+GMimeCryptoContext *g_mime_gpg_context_new (GMimePasswordRequestFunc request_passwd);
 
 gboolean g_mime_gpg_context_get_auto_key_retrieve (GMimeGpgContext *ctx);
 void g_mime_gpg_context_set_auto_key_retrieve (GMimeGpgContext *ctx, gboolean auto_key_retrieve);
 
-gboolean g_mime_gpg_context_get_use_agent (GMimeGpgContext *ctx);
-void g_mime_gpg_context_set_use_agent (GMimeGpgContext *ctx, gboolean use_agent);
-
 G_END_DECLS
 
 #endif /* __GMIME_GPG_CONTEXT_H__ */
diff --git a/gmime/gmime-pkcs7-context.c b/gmime/gmime-pkcs7-context.c
index 0a9829f..5374452 100644
--- a/gmime/gmime-pkcs7-context.c
+++ b/gmime/gmime-pkcs7-context.c
@@ -38,9 +38,7 @@
 #endif /* ENABLE_CRYPTO */
 #include "gmime-error.h"
 
-#ifdef ENABLE_CRYPTO
 #include <gpgme.h>
-#endif
 
 #ifdef ENABLE_DEBUG
 #define d(x) x
diff --git a/tests/test-pgp.c b/tests/test-pgp.c
index d6bcfb9..c69d64f 100644
--- a/tests/test-pgp.c
+++ b/tests/test-pgp.c
@@ -305,7 +305,7 @@ int main (int argc, char **argv)
        
        testsuite_start ("GnuPG crypto context");
        
-       ctx = g_mime_gpg_context_new (request_passwd, GPG_PATH);
+       ctx = g_mime_gpg_context_new (request_passwd);
        g_mime_crypto_context_set_always_trust (ctx, TRUE);
        
        testsuite_check ("GMimeGpgContext::import");
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index ade6f3b..482ea41 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -465,14 +465,14 @@ import_key (GMimeCryptoContext *ctx, const char *path)
 
 int main (int argc, char *argv[])
 {
+       GMimeStream *stream = NULL, *cleartext = NULL;
        const char *datadir = "data/pgpmime";
+       char *session_key = NULL;
        GMimeCryptoContext *ctx;
+       GError *err = NULL;
        struct stat st;
        char *key;
        int i;
-       GMimeStream *stream = NULL, *cleartext = NULL;
-       char *session_key = NULL;
-       GError *err = NULL;
        
        g_mime_init (0);
        
@@ -493,7 +493,7 @@ int main (int argc, char *argv[])
        
        testsuite_start ("PGP/MIME implementation");
        
-       ctx = g_mime_gpg_context_new (request_passwd, GPG_PATH);
+       ctx = g_mime_gpg_context_new (request_passwd);
        g_mime_crypto_context_set_always_trust (ctx, TRUE);
        if (g_mime_crypto_context_set_retrieve_session_key (ctx, TRUE, &err) != 0) {
                fprintf (stderr, "Failed to set retrieve_session_key on GMimeGpgContext: %s\n",
diff --git a/tests/testsuite.c b/tests/testsuite.c
index 9373c52..7d9c21e 100644
--- a/tests/testsuite.c
+++ b/tests/testsuite.c
@@ -360,12 +360,62 @@ g_throw (Exception *ex)
 
 #define v2_1_16 ((2 << 24) | (1 << 16) | (16 << 8))
 
-int _g_mime_get_gpg_version (const char *gpg);
+static int
+get_gpg_version (const char *path)
+{
+       const char vheader[] = "gpg (GnuPG) ";
+       int v, n = 0, version = 0;
+       const char *inptr;
+       char buffer[128];
+       char *command;
+       FILE *gpg;
+       
+       g_return_val_if_fail (path != NULL, -1);
+       
+       command = g_strdup_printf ("%s --version", path);
+       gpg = popen (command, "r");
+       g_free (command);
+       
+       if (gpg == NULL)
+               return -1;
+       
+       inptr = fgets (buffer, 128, gpg);
+       pclose (gpg);
+       
+       if (strncmp (inptr, vheader, sizeof (vheader) - 1) != 0)
+               return -1;
+       
+       inptr += sizeof (vheader) - 1;
+       while (*inptr >= '0' && *inptr <= '9' && n < 4) {
+               v = 0;
+               
+               while (*inptr >= '0' && *inptr <= '9' && (v < 25 || (v == 25 && *inptr < '6'))) {
+                       v = (v * 10) + (*inptr - '0');
+                       inptr++;
+               }
+               
+               version = (version << 8) + v;
+               n++;
+               
+               if (*inptr != '.')
+                       break;
+               
+               inptr++;
+       }
+       
+       if (n == 0)
+               return -1;
+       
+       if (n < 4)
+               version = version << ((4 - n) * 8);
+       
+       return version;
+}
 
 int
 testsuite_can_safely_override_session_key (const char *gpg)
 {
-       return _g_mime_get_gpg_version (gpg) >= v2_1_16;
+       return get_gpg_version (gpg) >= v2_1_16;
 }
 
 int
@@ -395,7 +445,7 @@ testsuite_setup_gpghome (const char *gpg)
        
        g_free (command);
        
-       if (_g_mime_get_gpg_version (gpg) >= ((2 << 24) | (1 << 16))) {
+       if (get_gpg_version (gpg) >= ((2 << 24) | (1 << 16))) {
                FILE *fp;
                
                if ((fp = fopen ("./tmp/.gnupg/gpg.conf", "w")) == NULL)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]