=?utf-8?q?=5Bbalsa/gtk3=5D_New_crypto_implementation_=28Albrecht_Dre?= =?utf-8?b?w58p?=



commit 989c0bb2d9a63e111c16eee33484bf2842b30cba
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date:   Sat Dec 10 18:00:07 2011 -0500

    New crypto implementation (Albrecht DreÃ)
    
    	* libbalsa/Makefile.am: new files.
    	* libbalsa/body.c (libbalsa_message_body_protect_state): use new
    	implementation.
    	* libbalsa/gmime-application-pkcs7.c
    	(g_mime_application_pkcs7_decrypt_verify),
    	(g_mime_application_pkcs7_encrypt): ditto.
    	* libbalsa/gmime-application-pkcs7.h: ditto.
    	* libbalsa/gmime-gpgme-context.c: new file.
    	* libbalsa/gmime-gpgme-context.h: ditto.
    	* libbalsa/gmime-gpgme-signature.c
    	(g_mime_gpgme_sigstat_new_from_gpgme_ctx),
    	(g_mime_gpgme_sigstat_finalize), (hex_decode),
    	(libbalsa_cert_subject_readable), (g_mime_gpgme_sigstat_init):
    	ditto.
    	* libbalsa/gmime-gpgme-signature.h: ditto.
    	* libbalsa/gmime-part-rfc2440.c (g_mime_part_check_rfc2440),
    	(g_mime_part_rfc2440_sign_encrypt), (g_mime_part_rfc2440_verify),
    	(g_mime_part_rfc2440_decrypt): use new implementation.
    	* libbalsa/gmime-part-rfc2440.h: ditto.
    	* libbalsa/rfc3156.c (libbalsa_sign_mime_object),
    	(libbalsa_encrypt_mime_object), (libbalsa_body_check_signature),
    	(libbalsa_body_decrypt), (libbalsa_rfc2440_sign_encrypt),
    	(libbalsa_rfc2440_verify), (libbalsa_rfc2440_decrypt),
    	(libbalsa_gpgme_validity_to_gchar_short), (append_time_t),
    	(libbalsa_signature_info_to_gchar): ditto.
    	* libbalsa/rfc3156.h: ditto.
    	* src/balsa-message.c (libbalsa_msg_part_2440): ditto.
    	* src/main.c (main): ditto.

 ChangeLog                          |   33 +
 libbalsa/Makefile.am               |   16 +-
 libbalsa/body.c                    |    2 +-
 libbalsa/gmime-application-pkcs7.c |  353 ++--------
 libbalsa/gmime-application-pkcs7.h |   61 +--
 libbalsa/gmime-gpgme-context.c     | 1415 ------------------------------------
 libbalsa/gmime-gpgme-context.h     |  125 ----
 libbalsa/gmime-gpgme-signature.c   |  199 +++---
 libbalsa/gmime-gpgme-signature.h   |   27 +-
 libbalsa/gmime-multipart-crypt.c   |  576 +++++++++++++++
 libbalsa/gmime-multipart-crypt.h   |   69 ++
 libbalsa/gmime-part-rfc2440.c      |  275 ++++----
 libbalsa/gmime-part-rfc2440.h      |   35 +-
 libbalsa/libbalsa-gpgme-cb.c       |  428 +++++++++++
 libbalsa/libbalsa-gpgme-cb.h       |   59 ++
 libbalsa/libbalsa-gpgme.c          |  968 ++++++++++++++++++++++++
 libbalsa/libbalsa-gpgme.h          |  115 +++
 libbalsa/rfc3156.c                 | 1276 +++++----------------------------
 libbalsa/rfc3156.h                 |    5 +-
 src/balsa-message.c                |    2 +-
 src/main.c                         |   56 +--
 21 files changed, 2741 insertions(+), 3354 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 52ad6f4..3763177 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2011-12-10  Albrecht DreÃ
+
+	New crypto implementation
+
+	* libbalsa/Makefile.am: new files.
+	* libbalsa/body.c (libbalsa_message_body_protect_state): use new
+	implementation.
+	* libbalsa/gmime-application-pkcs7.c
+	(g_mime_application_pkcs7_decrypt_verify),
+	(g_mime_application_pkcs7_encrypt): ditto.
+	* libbalsa/gmime-application-pkcs7.h: ditto.
+	* libbalsa/gmime-gpgme-context.c: new file.
+	* libbalsa/gmime-gpgme-context.h: ditto.
+	* libbalsa/gmime-gpgme-signature.c
+	(g_mime_gpgme_sigstat_new_from_gpgme_ctx),
+	(g_mime_gpgme_sigstat_finalize), (hex_decode),
+	(libbalsa_cert_subject_readable), (g_mime_gpgme_sigstat_init):
+	ditto.
+	* libbalsa/gmime-gpgme-signature.h: ditto.
+	* libbalsa/gmime-part-rfc2440.c (g_mime_part_check_rfc2440),
+	(g_mime_part_rfc2440_sign_encrypt), (g_mime_part_rfc2440_verify),
+	(g_mime_part_rfc2440_decrypt): use new implementation.
+	* libbalsa/gmime-part-rfc2440.h: ditto.
+	* libbalsa/rfc3156.c (libbalsa_sign_mime_object),
+	(libbalsa_encrypt_mime_object), (libbalsa_body_check_signature),
+	(libbalsa_body_decrypt), (libbalsa_rfc2440_sign_encrypt),
+	(libbalsa_rfc2440_verify), (libbalsa_rfc2440_decrypt),
+	(libbalsa_gpgme_validity_to_gchar_short), (append_time_t),
+	(libbalsa_signature_info_to_gchar): ditto.
+	* libbalsa/rfc3156.h: ditto.
+	* src/balsa-message.c (libbalsa_msg_part_2440): ditto.
+	* src/main.c (main): ditto.
+
 2011-12-03  Peter Bloomfield
 
 	* src/sendmsg-window.c (create_text_area): remove redundant
diff --git a/libbalsa/Makefile.am b/libbalsa/Makefile.am
index 525b04a..00bda16 100644
--- a/libbalsa/Makefile.am
+++ b/libbalsa/Makefile.am
@@ -5,8 +5,12 @@ noinst_LIBRARIES = libbalsa.a
 
 if BUILD_WITH_GPGME
 libbalsa_gpgme_extra = 		\
-	gmime-gpgme-context.h	\
-	gmime-gpgme-context.c	\
+	libbalsa-gpgme.h		\
+	libbalsa-gpgme.c		\
+	libbalsa-gpgme-cb.h		\
+	libbalsa-gpgme-cb.c		\
+	gmime-multipart-crypt.h	\
+	gmime-multipart-crypt.c	\
 	gmime-part-rfc2440.h	\
 	gmime-part-rfc2440.c	\
 	gmime-gpgme-signature.h	\
@@ -15,8 +19,12 @@ libbalsa_gpgme_extra_dist =
 else
 libbalsa_gpgme_extra =
 libbalsa_gpgme_extra_dist =	\
-	gmime-gpgme-context.h	\
-	gmime-gpgme-context.c	\
+	libbalsa-gpgme.h		\
+	libbalsa-gpgme.c		\
+	libbalsa-gpgme-cb.h		\
+	libbalsa-gpgme-cb.c		\
+	gmime-multipart-crypt.h	\
+	gmime-multipart-crypt.c	\
 	gmime-part-rfc2440.h	\
 	gmime-part-rfc2440.c	\
 	gmime-gpgme-signature.h	\
diff --git a/libbalsa/body.c b/libbalsa/body.c
index 9dd05de..22f1b04 100644
--- a/libbalsa/body.c
+++ b/libbalsa/body.c
@@ -851,7 +851,7 @@ libbalsa_message_body_protect_state(LibBalsaMessageBody *body)
 	   at least marginal */
 	if (body->sig_info->validity >= GPGME_VALIDITY_MARGINAL &&
 	    (body->sig_info->protocol == GPGME_PROTOCOL_CMS ||
-	     body->sig_info->trust >= GPGME_VALIDITY_MARGINAL))
+	     body->sig_info->key->owner_trust >= GPGME_VALIDITY_MARGINAL))
 	    return LIBBALSA_MSG_PROTECT_SIGN_GOOD;
 	else
 	    return LIBBALSA_MSG_PROTECT_SIGN_NOTRUST;
diff --git a/libbalsa/gmime-application-pkcs7.c b/libbalsa/gmime-application-pkcs7.c
index 63b8087..cad055c 100644
--- a/libbalsa/gmime-application-pkcs7.c
+++ b/libbalsa/gmime-application-pkcs7.c
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /*
  * S/MIME application/pkcs7-mime support for gmime/balsa
- * Copyright (C) 2004 Albrecht Dreß<albrecht dress arcor de>
+ * Copyright (C) 2004 Albrecht Dreà <albrecht dress arcor de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@
 #include <gmime/gmime-multipart.h>
 #include <gmime/gmime-multipart-signed.h>
 #include <gmime/gmime-multipart-encrypted.h>
+#include "libbalsa-gpgme.h"
 #include "gmime-application-pkcs7.h"
 #include <glib/gi18n.h>
 
@@ -42,137 +43,6 @@
 #define GMIME_PKCS7_ERR_QUARK (g_quark_from_static_string ("gmime-app-pkcs7"))
 
 
-#ifdef HAS_APPLICATION_PKCS7_MIME_SIGNED_SUPPORT
-
-/*
- * Note: this code has been shamelessly stolen from Jeff's multipart-signed implementation
- */
-static void
-sign_prepare (GMimeObject *mime_part)
-{
-    GMimeContentEncoding encoding;
-    GMimeObject *subpart;
-	
-    if (GMIME_IS_MULTIPART (mime_part)) {
-	GList *lpart;
-		
-	if (GMIME_IS_MULTIPART_SIGNED (mime_part) || GMIME_IS_MULTIPART_ENCRYPTED (mime_part)) {
-	    /* must not modify these parts as they must be treated as opaque */
-	    return;
-	}
-		
-	lpart = GMIME_MULTIPART (mime_part)->subparts;
-	while (lpart) {
-	    subpart = GMIME_OBJECT (lpart->data);
-	    sign_prepare (subpart);
-	    lpart = lpart->next;
-	}
-    } else if (GMIME_IS_MESSAGE_PART (mime_part)) {
-	subpart = GMIME_MESSAGE_PART (mime_part)->message->mime_part;
-	sign_prepare (subpart);
-    } else {
-	encoding = g_mime_part_get_content_encoding (GMIME_PART (mime_part));
-		
-	if (encoding != GMIME_CONTENT_ENCODING_BASE64)
-	    g_mime_part_set_content_encoding (GMIME_PART (mime_part),
-				      GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE);
-    }
-}
-
-
-/*
- * Sign content using the context ctx for userid and write the signed
- * application/pkcs7-mime object to pkcs7. Return 0 on success and -1 on error.
- * In the latter case, fill err with more information about the reason.
- */
-int
-g_mime_application_pkcs7_sign (GMimePart *pkcs7, GMimeObject *content,
-			       GMimeCipherContext *ctx, const char *userid,
-			       GError **err)
-{
-    GMimeDataWrapper *wrapper;
-    GMimeStream *filtered_stream;
-    GMimeStream *stream, *sig_data_stream;
-    GMimeFilter *crlf_filter, *from_filter;
-	
-    g_return_val_if_fail (GMIME_IS_PART (pkcs7), -1);
-#ifndef HAVE_GMIME_2_5_7
-    g_return_val_if_fail (GMIME_IS_CIPHER_CONTEXT (ctx), -1);
-    g_return_val_if_fail (ctx->sign_protocol != NULL, -1);
-#else /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), -1);
-    g_return_val_if_fail(g_mime_crypto_context_get_signature_protocol(ctx)
-                         != NULL, -1);
-#endif /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail (GMIME_IS_OBJECT (content), -1);
-	
-    /* Prepare all the parts for signing... */
-    sign_prepare (content);
-	
-    /* get the cleartext */
-    stream = g_mime_stream_mem_new ();
-    filtered_stream = g_mime_stream_filter_new (stream);
-	
-    /* See RFC 2633, Sect. 3.1- the following op's are "SHOULD", so we do it */
-    from_filter = g_mime_filter_from_new (GMIME_FILTER_FROM_MODE_ARMOR);
-    g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), from_filter);
-    g_object_unref (from_filter);
-	
-    g_mime_object_write_to_stream (content, filtered_stream);
-    g_mime_stream_flush (filtered_stream);
-    g_object_unref (filtered_stream);
-    g_mime_stream_reset (stream);
-	
-    filtered_stream = g_mime_stream_filter_new (stream);
-    crlf_filter = g_mime_filter_crlf_new (TRUE,
-					  FALSE);
-    g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), crlf_filter);
-    g_object_unref (crlf_filter);
-	
-    /* construct the signed data stream */
-    sig_data_stream = g_mime_stream_mem_new ();
-	
-    /* get the signed content */
-#ifndef HAVE_GMIME_2_5_7
-    if (g_mime_cipher_context_sign (ctx, userid, GMIME_CIPHER_HASH_DEFAULT, filtered_stream, sig_data_stream, err) == -1)
-#else /* HAVE_GMIME_2_5_7 */
-    if (g_mime_crypto_context_sign
-        (ctx, userid, GMIME_CIPHER_HASH_DEFAULT, filtered_stream,
-         sig_data_stream, err) == -1)
-#endif /* HAVE_GMIME_2_5_7 */
-    {
-	g_object_unref (filtered_stream);
-	g_object_unref (sig_data_stream);
-	g_object_unref (stream);
-	return -1;
-    }
-	
-    g_object_unref (filtered_stream);
-    g_object_unref (stream);
-    g_mime_stream_reset (sig_data_stream);
-	
-    /* set the pkcs7 mime part as content of the pkcs7 object */
-    wrapper = g_mime_data_wrapper_new();
-    g_mime_data_wrapper_set_stream(wrapper, sig_data_stream);
-    g_object_unref(sig_data_stream);
-    g_mime_part_set_content_object(GMIME_PART(pkcs7), wrapper);
-    g_mime_part_set_filename(GMIME_PART(pkcs7), "smime.p7m");
-    g_mime_part_set_content_encoding(GMIME_PART(pkcs7),
-			     GMIME_CONTENT_ENCODING_BASE64);
-    g_object_unref(wrapper);
-
-    /* set the content-type params for this part */
-    g_mime_object_set_content_type_parameter(GMIME_OBJECT(pkcs7),
-					     "smime-type", "signed-data");
-    g_mime_object_set_content_type_parameter(GMIME_OBJECT(pkcs7), "name",
-					     "smime.p7m");
-	
-    return 0;
-}
-#endif /* HAS_APPLICATION_PKCS7_MIME_SIGNED_SUPPORT */
-
-
-
 /*
  * Try to verify pkcs7 using the context ctx, fill validity with the resulting
  * validity and return the "readable" decrypted part. If anything fails, the
@@ -181,15 +51,9 @@ g_mime_application_pkcs7_sign (GMimePart *pkcs7, GMimeObject *content,
  * decrypting it again. In this case, validity is undefined.
  */
 GMimeObject *
-#ifndef HAVE_GMIME_2_5_7
-g_mime_application_pkcs7_verify(GMimePart * pkcs7,
-				GMimeSignatureValidity ** validity,
-				GMimeCipherContext * ctx, GError ** err)
-#else /* HAVE_GMIME_2_5_7 */
-g_mime_application_pkcs7_verify(GMimePart * pkcs7,
-                                GMimeSignatureList ** list,
-                                GMimeCryptoContext * ctx, GError ** err)
-#endif /* HAVE_GMIME_2_5_7 */
+g_mime_application_pkcs7_decrypt_verify(GMimePart * pkcs7,
+					GMimeGpgmeSigstat ** signature,
+					GtkWindow * parent, GError ** err)
 {
     GMimeObject *decrypted;
     GMimeDataWrapper *wrapper;
@@ -200,49 +64,41 @@ g_mime_application_pkcs7_verify(GMimePart * pkcs7,
     const char *smime_type;
 
     g_return_val_if_fail(GMIME_IS_PART(pkcs7), NULL);
-#ifndef HAVE_GMIME_2_5_7
-    g_return_val_if_fail(GMIME_IS_CIPHER_CONTEXT(ctx), NULL);
-    g_return_val_if_fail(ctx->encrypt_protocol != NULL, NULL);
-#else /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail(GMIME_IS_CRYPTO_CONTEXT(ctx), NULL);
-    g_return_val_if_fail(g_mime_crypto_context_get_encryption_protocol(ctx)
-                         != NULL, NULL);
-#endif /* HAVE_GMIME_2_5_7 */
 
-    /* some sanity checks */
+    /* get the smime type */
     smime_type =
 	g_mime_object_get_content_type_parameter(GMIME_OBJECT(pkcs7),
 						 "smime-type");
-    if (g_ascii_strcasecmp(smime_type, "signed-data")) {
+    if (!smime_type
+	|| (g_ascii_strcasecmp(smime_type, "enveloped-data")
+	    && g_ascii_strcasecmp(smime_type, "signed-data"))) {
 	return NULL;
     }
 
     /* get the ciphertext stream */
     wrapper = g_mime_part_get_content_object(GMIME_PART(pkcs7));
     g_return_val_if_fail(wrapper, NULL); /* Incomplete part. */
-    ciphertext = g_mime_stream_mem_new ();
-    g_mime_data_wrapper_write_to_stream (wrapper, ciphertext);
+    ciphertext = g_mime_stream_mem_new();
+    g_mime_data_wrapper_write_to_stream(wrapper, ciphertext);
     g_mime_stream_reset(ciphertext);
 
     stream = g_mime_stream_mem_new();
     filtered_stream = g_mime_stream_filter_new(stream);
-    crlf_filter = g_mime_filter_crlf_new(FALSE,
-					 FALSE);
+    crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE);
     g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
 			     crlf_filter);
     g_object_unref(crlf_filter);
 
     /* get the cleartext */
-#ifndef HAVE_GMIME_2_5_7
-    *validity = g_mime_cipher_context_verify(ctx, GMIME_CIPHER_HASH_DEFAULT,
-				     ciphertext, filtered_stream, err);
-    if (!*validity)
-#else /* HAVE_GMIME_2_5_7 */
-    *list = g_mime_crypto_context_verify(ctx, GMIME_CIPHER_ALGO_DEFAULT,
-                                         ciphertext, filtered_stream, err);
-    if (!*list)
-#endif /* HAVE_GMIME_2_5_7 */
-    {
+    if (g_ascii_strcasecmp(smime_type, "enveloped-data") == 0)
+	*signature =
+	    libbalsa_gpgme_decrypt(ciphertext, filtered_stream,
+				   GPGME_PROTOCOL_CMS, parent, err);
+    else
+	*signature =
+	    libbalsa_gpgme_verify(ciphertext, filtered_stream,
+				  GPGME_PROTOCOL_CMS, TRUE, err);
+    if (!*signature) {
 	g_object_unref(filtered_stream);
 	g_object_unref(ciphertext);
 	g_object_unref(stream);
@@ -279,65 +135,47 @@ g_mime_application_pkcs7_verify(GMimePart * pkcs7,
  * about the reason.
  */
 int
-g_mime_application_pkcs7_encrypt (GMimePart *pkcs7, GMimeObject *content,
-#ifndef HAVE_GMIME_2_5_7
-				  GMimeCipherContext *ctx, GPtrArray *recipients,
-#else /* HAVE_GMIME_2_5_7 */
-				  GMimeCryptoContext *ctx,
-                                  GPtrArray *recipients,
-#endif /* HAVE_GMIME_2_5_7 */
-				  GError **err)
+g_mime_application_pkcs7_encrypt(GMimePart * pkcs7, GMimeObject * content,
+				 GPtrArray * recipients,
+				 gboolean trust_all, GtkWindow * parent,
+				 GError ** err)
 {
     GMimeDataWrapper *wrapper;
     GMimeStream *filtered_stream;
     GMimeStream *stream, *ciphertext;
     GMimeFilter *crlf_filter;
 	
-    g_return_val_if_fail (GMIME_IS_PART (pkcs7), -1);
-#ifndef HAVE_GMIME_2_5_7
-    g_return_val_if_fail (GMIME_IS_CIPHER_CONTEXT (ctx), -1);
-    g_return_val_if_fail (ctx->encrypt_protocol != NULL, -1);
-#else /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), -1);
-    g_return_val_if_fail(g_mime_crypto_context_get_encryption_protocol(ctx)
-                         != NULL, -1);
-#endif /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail (GMIME_IS_OBJECT (content), -1);
+    g_return_val_if_fail(GMIME_IS_PART(pkcs7), -1);
+    g_return_val_if_fail(GMIME_IS_OBJECT(content), -1);
 	
     /* get the cleartext */
-    stream = g_mime_stream_mem_new ();
-    filtered_stream = g_mime_stream_filter_new (stream);
+    stream = g_mime_stream_mem_new();
+    filtered_stream = g_mime_stream_filter_new(stream);
 	
-    crlf_filter = g_mime_filter_crlf_new (TRUE,
-					  FALSE);
-    g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), crlf_filter);
-    g_object_unref (crlf_filter);
+    crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE);
+    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
+			     crlf_filter);
+    g_object_unref(crlf_filter);
 	
-    g_mime_object_write_to_stream (content, filtered_stream);
-    g_mime_stream_flush (filtered_stream);
-    g_object_unref (filtered_stream);
+    g_mime_object_write_to_stream(content, filtered_stream);
+    g_mime_stream_flush(filtered_stream);
+    g_object_unref(filtered_stream);
 	
     /* reset the content stream */
-    g_mime_stream_reset (stream);
+    g_mime_stream_reset(stream);
 	
     /* encrypt the content stream */
-    ciphertext = g_mime_stream_mem_new ();
-#ifndef HAVE_GMIME_2_5_7
-    if (g_mime_cipher_context_encrypt (ctx, FALSE, NULL, recipients, stream, ciphertext, err) == -1)
-#else /* HAVE_GMIME_2_5_7 */
-    if (g_mime_crypto_context_encrypt
-        (ctx, FALSE, NULL,
-         GMIME_CIPHER_ALGO_DEFAULT,
-         recipients, stream, ciphertext, err) == -1)
-#endif /* HAVE_GMIME_2_5_7 */
-    {
-	g_object_unref (ciphertext);
-	g_object_unref (stream);
+    ciphertext = g_mime_stream_mem_new();
+    if (libbalsa_gpgme_encrypt
+	(recipients, NULL, stream, ciphertext, GPGME_PROTOCOL_CMS, TRUE,
+	 trust_all, parent, err) == -1) {
+	g_object_unref(ciphertext);
+	g_object_unref(stream);
 	return -1;
     }
 	
-    g_object_unref (stream);
-    g_mime_stream_reset (ciphertext);
+    g_object_unref(stream);
+    g_mime_stream_reset(ciphertext);
 	
     /* set the encrypted mime part as content of the pkcs7 object */
     wrapper = g_mime_data_wrapper_new();
@@ -345,109 +183,16 @@ g_mime_application_pkcs7_encrypt (GMimePart *pkcs7, GMimeObject *content,
     g_object_unref(ciphertext);
     g_mime_part_set_content_object(GMIME_PART(pkcs7), wrapper);
     g_mime_part_set_filename(GMIME_PART(pkcs7), "smime.p7m");
-    g_mime_part_set_content_encoding(GMIME_PART(pkcs7), GMIME_CONTENT_ENCODING_BASE64);
+    g_mime_part_set_content_encoding(GMIME_PART(pkcs7),
+				     GMIME_CONTENT_ENCODING_BASE64);
     g_object_unref(wrapper);
 
     /* set the content-type params for this part */
     g_mime_object_set_content_type_parameter(GMIME_OBJECT(pkcs7),
-					     "smime-type", "enveloped-data");
+					     "smime-type",
+					     "enveloped-data");
     g_mime_object_set_content_type_parameter(GMIME_OBJECT(pkcs7), "name",
 					     "smime.p7m");
 	
     return 0;
 }
-
-
-/*
- * Decrypt the application/pkcs7-mime part pkcs7 unsing the context ctx and
- * return the decrypted gmime object or NULL on error. In the latter case, fill
- * err with more information about the reason.
- */
-GMimeObject *
-#ifndef HAVE_GMIME_2_5_7
-g_mime_application_pkcs7_decrypt (GMimePart *pkcs7, GMimeCipherContext *ctx,
-				  GError **err)
-#else /* HAVE_GMIME_2_5_7 */
-g_mime_application_pkcs7_decrypt (GMimePart *pkcs7,
-                                  GMimeCryptoContext *ctx,
-				  GError **err)
-#endif /* HAVE_GMIME_2_5_7 */
-{
-    GMimeObject *decrypted;
-    GMimeDataWrapper *wrapper;
-    GMimeStream *stream, *ciphertext;
-    GMimeStream *filtered_stream;
-    GMimeFilter *crlf_filter;
-    GMimeParser *parser;
-    const char *smime_type;
-
-    g_return_val_if_fail(GMIME_IS_PART(pkcs7), NULL);
-#ifndef HAVE_GMIME_2_5_7
-    g_return_val_if_fail(GMIME_IS_CIPHER_CONTEXT(ctx), NULL);
-    g_return_val_if_fail(ctx->encrypt_protocol != NULL, NULL);
-#else /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail(GMIME_IS_CRYPTO_CONTEXT(ctx), NULL);
-    g_return_val_if_fail(g_mime_crypto_context_get_encryption_protocol(ctx)
-                         != NULL, NULL);
-#endif /* HAVE_GMIME_2_5_7 */
-
-    /* some sanity checks */
-    smime_type =
-	g_mime_object_get_content_type_parameter(GMIME_OBJECT(pkcs7),
-						 "smime-type");
-    if (!smime_type || (g_ascii_strcasecmp(smime_type, "enveloped-data") &&
-			g_ascii_strcasecmp(smime_type, "signed-data"))) {
-	return NULL;
-    }
-
-    /* get the ciphertext stream */
-    wrapper = g_mime_part_get_content_object(GMIME_PART(pkcs7));
-    g_return_val_if_fail(wrapper, NULL); /* Incomplete part. */
-    ciphertext = g_mime_stream_mem_new();
-    g_mime_data_wrapper_write_to_stream (wrapper, ciphertext);
-    g_mime_stream_reset(ciphertext);
-
-    stream = g_mime_stream_mem_new();
-    filtered_stream = g_mime_stream_filter_new(stream);
-    crlf_filter = g_mime_filter_crlf_new(FALSE,
-					 FALSE);
-    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
-			     crlf_filter);
-    g_object_unref(crlf_filter);
-
-    /* get the cleartext */
-#ifndef HAVE_GMIME_2_5_7
-    if (g_mime_cipher_context_decrypt(ctx, ciphertext, filtered_stream, err) == NULL)
-#else /* HAVE_GMIME_2_5_7 */
-    if (g_mime_crypto_context_decrypt
-        (ctx, ciphertext, filtered_stream, err) == NULL)
-#endif /* HAVE_GMIME_2_5_7 */
-    {
-	g_object_unref(filtered_stream);
-	g_object_unref(ciphertext);
-	g_object_unref(stream);
-
-	return NULL;
-    }
-
-    g_mime_stream_flush(filtered_stream);
-    g_object_unref(filtered_stream);
-    g_object_unref(ciphertext);
-
-    g_mime_stream_reset (stream);
-    parser = g_mime_parser_new();
-    g_mime_parser_init_with_stream(parser, stream);
-    g_object_unref(stream);
-
-    decrypted = g_mime_parser_construct_part(parser);
-    g_object_unref(parser);
-
-    if (decrypted)
-	g_object_ref(decrypted);
-    else
-	g_set_error(err, GMIME_PKCS7_ERR_QUARK, 42,
-		    _("Failed to decrypt MIME part: parse error"));
-
-    return decrypted;
-}
-
diff --git a/libbalsa/gmime-application-pkcs7.h b/libbalsa/gmime-application-pkcs7.h
index 6678ff5..6b9e0e7 100644
--- a/libbalsa/gmime-application-pkcs7.h
+++ b/libbalsa/gmime-application-pkcs7.h
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /*
  * S/MIME application/pkcs7-mime support for gmime/balsa
- * Copyright (C) 2004 Albrecht Dreß<albrecht dress arcor de>
+ * Copyright (C) 2004 Albrecht Dreà <albrecht dress arcor de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,56 +27,21 @@ extern "C" {
 #pragma }
 #endif				/* __cplusplus */
 
-#include <gmime/gmime-part.h>
-#ifndef HAVE_GMIME_2_5_7
-#include <gmime/gmime-cipher-context.h>
-#else /* HAVE_GMIME_2_5_7 */
-#include <gmime/gmime-crypto-context.h>
-#endif /* HAVE_GMIME_2_5_7 */
+#include <gmime/gmime.h>
 
-#undef HAS_APPLICATION_PKCS7_MIME_SIGNED_SUPPORT
 
-
-#ifdef HAS_APPLICATION_PKCS7_MIME_SIGNED_SUPPORT
-/* Note: application/pkcs7-mime signed parts are not used within balsa, as
- * they can not be viewed by mMUA's without S/MIME support. Therefore,
- * Balsa always encodes S/MIME signed stuff as multipart/signed. */
-int g_mime_application_pkcs7_sign(GMimePart * pkcs7,
+    GMimeObject *g_mime_application_pkcs7_decrypt_verify(GMimePart * pkcs7,
+							 GMimeGpgmeSigstat
+							 ** signature,
+							 GtkWindow *
+							 parent,
+							 GError ** err);
+    int g_mime_application_pkcs7_encrypt(GMimePart * pkcs7,
 				  GMimeObject * content,
-#ifndef HAVE_GMIME_2_5_7
-				  GMimeCipherContext * ctx,
-#else /* HAVE_GMIME_2_5_7 */
-				  GMimeCryptoContext * ctx,
-#endif /* HAVE_GMIME_2_5_7 */
-				  const char *userid, GError ** err);
-#endif
-
-#ifndef HAVE_GMIME_2_5_7
-GMimeObject *g_mime_application_pkcs7_verify(GMimePart * pkcs7,
-					     GMimeSignatureValidity ** validity,
-					     GMimeCipherContext * ctx, GError ** err);
-#else /* HAVE_GMIME_2_5_7 */
-GMimeObject *g_mime_application_pkcs7_verify(GMimePart * pkcs7,
-					     GMimeSignatureList ** validity,
-					     GMimeCryptoContext * ctx, GError ** err);
-#endif /* HAVE_GMIME_2_5_7 */
-
-int g_mime_application_pkcs7_encrypt(GMimePart * pkcs7,
-				     GMimeObject * content,
-#ifndef HAVE_GMIME_2_5_7
-				     GMimeCipherContext * ctx,
-#else /* HAVE_GMIME_2_5_7 */
-				     GMimeCryptoContext * ctx,
-#endif /* HAVE_GMIME_2_5_7 */
-				     GPtrArray * recipients, GError ** err);
-
-#ifndef HAVE_GMIME_2_5_7
-GMimeObject *g_mime_application_pkcs7_decrypt(GMimePart * pkcs7,
-					      GMimeCipherContext * ctx, GError ** err);
-#else /* HAVE_GMIME_2_5_7 */
-GMimeObject *g_mime_application_pkcs7_decrypt(GMimePart * pkcs7,
-					      GMimeCryptoContext * ctx, GError ** err);
-#endif /* HAVE_GMIME_2_5_7 */
+					 GPtrArray * recipients,
+					 gboolean trust_all,
+					 GtkWindow * parent,
+					 GError ** err);
 
 #ifdef __cplusplus
 }
diff --git a/libbalsa/gmime-gpgme-signature.c b/libbalsa/gmime-gpgme-signature.c
index d78441b..b1b67d0 100644
--- a/libbalsa/gmime-gpgme-signature.c
+++ b/libbalsa/gmime-gpgme-signature.c
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /*
  * gmime/gpgme glue layer library
- * Copyright (C) 2004 Albrecht Dreß<albrecht dress arcor de>
+ * Copyright (C) 2004-2011 Albrecht Dreà <albrecht dress arcor de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,10 +23,11 @@
 # include "config.h"
 #endif                          /* HAVE_CONFIG_H */
 
+#include <ctype.h>
 #include <gpgme.h>
 #include <string.h>
 #include <glib.h>
-#include "gmime-gpgme-context.h"
+#include "libbalsa-gpgme.h"
 #include "gmime-gpgme-signature.h"
 
 
@@ -37,7 +38,6 @@ static void g_mime_gpgme_sigstat_class_init(GMimeGpgmeSigstatClass *
 					    klass);
 static void g_mime_gpgme_sigstat_finalize(GMimeGpgmeSigstat * self);
 static void g_mime_gpgme_sigstat_init(GMimeGpgmeSigstat * self);
-static gchar *fix_EMail_info(gchar * str);
 
 
 /* GMimeGpgmeSigstat related stuff */
@@ -83,9 +83,6 @@ g_mime_gpgme_sigstat_new_from_gpgme_ctx(gpgme_ctx_t ctx)
 {
     GMimeGpgmeSigstat *sig_stat;
     gpgme_verify_result_t result;
-    gpgme_key_t key;
-    gpgme_subkey_t subkey;
-    gpgme_user_id_t uid;
     gpgme_error_t err;
 
     g_return_val_if_fail(ctx, NULL);
@@ -104,53 +101,14 @@ g_mime_gpgme_sigstat_new_from_gpgme_ctx(gpgme_ctx_t ctx)
     sig_stat->fingerprint = g_strdup(result->signatures->fpr);
     sig_stat->sign_time = result->signatures->timestamp;
     sig_stat->status = gpgme_err_code(result->signatures->status);
+    sig_stat->validity = result->signatures->validity;
 
     /* try to get the related key */
-    err = gpgme_get_key(ctx, sig_stat->fingerprint, &key, 0);
-    if (err != GPG_ERR_NO_ERROR) {
+    err = gpgme_get_key(ctx, sig_stat->fingerprint, &sig_stat->key, 0);
+    if (err != GPG_ERR_NO_ERROR)
           g_message("could not retrieve the key with fingerprint %s: %s: %s",
                     sig_stat->fingerprint, gpgme_strsource(err),
                     gpgme_strerror(err));
-	return sig_stat;
-    }
-    if (key == NULL)
-	return sig_stat;
-
-    /* the key is available */
-    sig_stat->protocol = key->protocol;
-    sig_stat->issuer_serial = g_strdup(key->issuer_serial);
-    sig_stat->issuer_name = g_strdup(key->issuer_name);
-    sig_stat->chain_id = g_strdup(key->chain_id);
-    sig_stat->trust = key->owner_trust;
-    uid = key->uids;
-
-    /* Note: there is no way to determine which user id has been used to
-     * create the signature. We therefore pick the validity of the primary
-     * one and scan uid's to get useable name, email and uid strings */
-    sig_stat->validity = uid->validity;
-    while (uid) {
-	if (!sig_stat->sign_name && uid->name && *uid->name)
-	    sig_stat->sign_name = g_strdup(uid->name);
-	if (!sig_stat->sign_email && uid->email && *uid->email)
-	    sig_stat->sign_email = g_strdup(uid->email);
-	if (!sig_stat->sign_uid && uid->uid && *uid->uid)
-	    sig_stat->sign_uid = fix_EMail_info(g_strdup(uid->uid));
-	uid = uid->next;
-    }
-
-    /* get the subkey which can sign */
-    subkey = key->subkeys;
-    while (subkey && !subkey->can_sign)
-	subkey = subkey->next;
-    if (subkey) {
-	sig_stat->key_created = subkey->timestamp;
-	sig_stat->key_expires = subkey->expires;
-	sig_stat->key_revoked = subkey->revoked;
-	sig_stat->key_expired = subkey->expired;
-	sig_stat->key_disabled = subkey->disabled;
-	sig_stat->key_invalid = subkey->invalid;
-    }
-    gpgme_key_unref(key);
 
     return sig_stat;
 }
@@ -166,84 +124,107 @@ g_mime_gpgme_sigstat_class_init(GMimeGpgmeSigstatClass * klass)
 	(GObjectFinalizeFunc) g_mime_gpgme_sigstat_finalize;
 }
 
-
 static void
 g_mime_gpgme_sigstat_finalize(GMimeGpgmeSigstat * self)
 {
-    g_free(self->sign_name);
-    self->sign_name = NULL;
-    g_free(self->sign_email);
-    self->sign_email = NULL;
     g_free(self->fingerprint);
     self->fingerprint = NULL;
-    g_free(self->sign_uid);
-    self->sign_uid = NULL;
-    g_free(self->issuer_serial);
-    self->issuer_serial = NULL;
-    g_free(self->issuer_name);
-    self->issuer_name = NULL;
-    g_free(self->chain_id);
-    self->chain_id = NULL;
+    if (self->key)
+	gpgme_key_unref(self->key);
+    self->key = NULL;
 
     g_mime_gpgme_sigstat_parent_class->finalize(G_OBJECT(self));
 }
 
-
-static void
-g_mime_gpgme_sigstat_init(GMimeGpgmeSigstat * self)
+static gchar *
+hex_decode(const gchar *hexstr)
 {
-    self->status = GPG_ERR_NOT_SIGNED;
-    self->sign_name = NULL;
-    self->sign_email = NULL;
-    self->fingerprint = NULL;
-    self->sign_uid = NULL;
-    self->issuer_serial = NULL;
-    self->issuer_name = NULL;
-    self->chain_id = NULL;
+    gchar *result;
+    gchar *outp;
+    int inlen;
+
+    inlen = strlen(hexstr);
+    if ((inlen & 1) == 1)
+        return g_strdup(hexstr);
+
+    result = g_new0(gchar, (inlen >> 1) + 1);
+    for (outp = result; *hexstr; outp++) {
+        if (isdigit(*hexstr))
+            *outp = (*hexstr - '0') << 4;
+        else
+            *outp = (toupper(*hexstr) -'A' + 10) << 4;
+        hexstr++;
+        if (isdigit(*hexstr))
+            *outp |= *hexstr - '0';
+        else
+            *outp |= toupper(*hexstr) -'A' + 10;
+        hexstr++;
+    }
+    return result;
 }
 
-
 /*
- * Change an EMail field in a S/MIME certificate to human-readable text.
+ * Change some fields in a S/MIME certificate to human-readable text.
  * Note: doesn't do any sophisticated error-checking...
  */
-static gchar *
-fix_EMail_info(gchar * str)
+gchar *
+libbalsa_cert_subject_readable(const gchar *subject)
 {
-    gchar *p = strstr(str, "1.2.840.113549.1.9.1=#");
+    const struct {
+        gchar *ldap_id;
+        gchar *readable;
+    } ldap_id_list[] = {
+        { .ldap_id = "2.5.4.4", .readable = "sn" },
+        { .ldap_id = "2.5.4.5", .readable = "serialNumber" },
+        { .ldap_id = "2.5.4.42", .readable = "givenName" },
+        { .ldap_id = "1.2.840.113549.1.9.1", .readable = "email" },
+        { .ldap_id = NULL, .readable = NULL }
+    }, *ldap_elem;
+    gchar **elements;
+    gint n;
     GString *result;
 
-    if (!p)
-	return str;
-
-    *p = '\0';
-    p += 22;
-    result = g_string_new(str);
-    result = g_string_append(result, "EMail=");
-    while (*p != '\0' && *p != ',') {
-	gchar x = 0;
-
-	if (*p >= 'A' && *p <= 'F')
-	    x = (*p - 'A' + 10) << 4;
-	else if (*p >= 'a' && *p <= 'f')
-	    x = (*p - 'a' + 10) << 4;
-	else if (*p >= '0' && *p <= '9')
-	    x = (*p - '0') << 4;
-	p++;
-	if (*p != '\0' && *p != ',') {
-	    if (*p >= 'A' && *p <= 'F')
-		x += *p - 'A' + 10;
-	    else if (*p >= 'a' && *p <= 'f')
-		x += *p - 'a' + 10;
-	    else if (*p >= '0' && *p <= '9')
-		x += *p - '0';
-	    p++;
-	}
-	result = g_string_append_c(result, x);
+    if (!subject)
+        return NULL;
+
+    result = g_string_new(NULL);
+    elements = g_strsplit(subject, ",", -1);
+    for (n = 0; elements[n]; n++) {
+        gchar *equals;
+
+        equals = strchr(elements[n], '=');
+        if (equals) {
+            *equals++ = '\0';
+            for (ldap_elem = ldap_id_list;
+                 ldap_elem->ldap_id && strcmp(ldap_elem->ldap_id, elements[n]);
+                 ldap_elem++);
+            if (ldap_elem->ldap_id)
+                result = g_string_append(result, ldap_elem->readable);
+            else
+                result = g_string_append(result, elements[n]);
+            result = g_string_append_c(result, '=');
+            
+            if (*equals == '#') {
+                gchar *decoded;
+
+                decoded = hex_decode(equals + 1);
+                result = g_string_append(result, decoded);
+                g_free(decoded);
+            } else
+                result = g_string_append(result, equals);
+        } else
+            result = g_string_append(result, elements[n]);
+        if (elements[n + 1])
+            result = g_string_append_c(result, ',');
     }
-    result = g_string_append(result, p);
-    g_free(str);
-    p = result->str;
-    g_string_free(result, FALSE);
-    return p;
+    g_strfreev(elements);
+    return g_string_free(result, FALSE);
+}
+
+static void
+g_mime_gpgme_sigstat_init(GMimeGpgmeSigstat * self)
+{
+    self->status = GPG_ERR_NOT_SIGNED;
+    self->key = NULL;
+    self->fingerprint = NULL;
 }
diff --git a/libbalsa/gmime-gpgme-signature.h b/libbalsa/gmime-gpgme-signature.h
index 73a2dfa..f036af9 100644
--- a/libbalsa/gmime-gpgme-signature.h
+++ b/libbalsa/gmime-gpgme-signature.h
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /*
  * gmime/gpgme glue layer library
- * Copyright (C) 2004 Albrecht Dreß<albrecht dress arcor de>
+ * Copyright (C) 2004-2011 Albrecht Dreà <albrecht dress arcor de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 #define __GMIME_GPGME_SIGNATURE_H__
 
 #include <gpgme.h>
-#include <glib-object.h>
+#include <glib.h>
 
 
 #ifdef __cplusplus
@@ -43,30 +43,20 @@ extern "C" {
 
 typedef struct _GMimeGpgmeSigstat GMimeGpgmeSigstat;
 typedef struct _GMimeGpgmeSigstatClass GMimeGpgmeSigstatClass;
-
+typedef struct _sig_uid_t sig_uid_t;
 
 struct _GMimeGpgmeSigstat {
     GObject parent;
 
-    /* various data gathered by gpgme's verify */
+    /* results form gpgme's verify operation */
     gpgme_protocol_t protocol;
     gpgme_error_t status;
     gpgme_validity_t validity;
-    gpgme_validity_t trust;
-    gchar *sign_name;
-    gchar *sign_email;
     gchar *fingerprint;
-    gchar *sign_uid;
-    gchar *issuer_serial;
-    gchar *issuer_name;
-    gchar *chain_id;
-    time_t key_created;
-    time_t key_expires;
-    gboolean key_revoked;
-    gboolean key_expired;
-    gboolean key_disabled;
-    gboolean key_invalid;
     time_t sign_time;
+
+    /* information about the key used to create the signature */
+    gpgme_key_t key;
 };
 
 struct _GMimeGpgmeSigstatClass {
@@ -79,6 +69,9 @@ GMimeGpgmeSigstat *g_mime_gpgme_sigstat_new(void);
 GMimeGpgmeSigstat *g_mime_gpgme_sigstat_new_from_gpgme_ctx(gpgme_ctx_t
 							   ctx);
 
+gchar *libbalsa_cert_subject_readable(const gchar *subject);
+
+
 #ifdef __cplusplus
 }
 #endif				/* __cplusplus */
diff --git a/libbalsa/gmime-multipart-crypt.c b/libbalsa/gmime-multipart-crypt.c
new file mode 100644
index 0000000..17b59fd
--- /dev/null
+++ b/libbalsa/gmime-multipart-crypt.c
@@ -0,0 +1,576 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * gmime/gpgme implementation for multipart/signed and multipart/encrypted
+ * Copyright (C) 2011 Albrecht Dreà <albrecht dress arcor de>
+ *
+ * The functions in this module were copied from the original GMime
+ * implementation of multipart/signed and multipart/encrypted parts.
+ * However, instead of using the complex GMime crypto contexts (which have
+ * a varying API over the different versions), this module directly calls
+ * the GpgME backend functions implemented in libbalsa-gpgme.[hc].
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option) 
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+ * GNU General Public License for more details.
+ *  
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
+ * 02111-1307, USA.
+ */
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+#include "config.h"
+#endif				/* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <unistd.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include "libbalsa-gpgme.h"
+#include "gmime-multipart-crypt.h"
+
+
+/**
+ * sign_prepare:
+ * @mime_part: MIME part
+ *
+ * Prepare a part (and all subparts) to be signed. To do this we need
+ * to set the encoding of all parts (that are not already encoded to
+ * either QP or Base64) to QP.
+ **/
+static void
+sign_prepare(GMimeObject * mime_part)
+{
+    GMimeContentEncoding encoding;
+    GMimeMultipart *multipart;
+    GMimeObject *subpart;
+    int i, n;
+
+    if (GMIME_IS_MULTIPART(mime_part)) {
+	multipart = (GMimeMultipart *) mime_part;
+
+	if (GMIME_IS_MULTIPART_SIGNED(multipart) ||
+	    GMIME_IS_MULTIPART_ENCRYPTED(multipart)) {
+	    /* must not modify these parts as they must be treated as opaque */
+	    return;
+	}
+
+	n = g_mime_multipart_get_count(multipart);
+	for (i = 0; i < n; i++) {
+	    subpart = g_mime_multipart_get_part(multipart, i);
+	    sign_prepare(subpart);
+	}
+    } else if (GMIME_IS_MESSAGE_PART(mime_part)) {
+	subpart = GMIME_MESSAGE_PART(mime_part)->message->mime_part;
+	sign_prepare(subpart);
+    } else {
+	encoding = g_mime_part_get_content_encoding(GMIME_PART(mime_part));
+	if (encoding != GMIME_CONTENT_ENCODING_BASE64)
+	    g_mime_part_set_content_encoding(GMIME_PART(mime_part),
+					     GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE);
+    }
+}
+
+
+int
+g_mime_gpgme_mps_sign(GMimeMultipartSigned * mps, GMimeObject * content,
+		      const gchar * userid, gpgme_protocol_t protocol,
+		      GtkWindow * parent, GError ** err)
+{
+    GMimeStream *stream;
+    GMimeStream *filtered;
+    GMimeStream *sigstream;
+    GMimeFilter *filter;
+    GMimeContentType *content_type;
+    GMimeDataWrapper *wrapper;
+    GMimeParser *parser;
+    GMimePart *signature;
+    const gchar *sig_type;
+    gpgme_hash_algo_t hash_algo;
+
+    g_return_val_if_fail(GMIME_IS_MULTIPART_SIGNED(mps), -1);
+    g_return_val_if_fail(GMIME_IS_OBJECT(content), -1);
+
+    /* Prepare all the parts for signing... */
+    sign_prepare(content);
+
+    /* get the cleartext */
+    stream = g_mime_stream_mem_new();
+    filtered = g_mime_stream_filter_new(stream);
+
+    /* Note: see rfc3156, section 3 - second note */
+    filter = g_mime_filter_from_new(GMIME_FILTER_FROM_MODE_ARMOR);
+    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter);
+    g_object_unref(filter);
+
+    /* Note: see rfc3156, section 5.4 (this is the main difference between rfc2015 and rfc3156) */
+    filter = g_mime_filter_strip_new();
+    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter);
+    g_object_unref(filter);
+
+    g_mime_object_write_to_stream(content, filtered);
+    g_mime_stream_flush(filtered);
+    g_object_unref(filtered);
+    g_mime_stream_reset(stream);
+
+    /* Note: see rfc2015 or rfc3156, section 5.1 */
+    filtered = g_mime_stream_filter_new(stream);
+    filter = g_mime_filter_crlf_new(TRUE, FALSE);
+    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter);
+    g_object_unref(filter);
+
+    /* construct the signature stream */
+    sigstream = g_mime_stream_mem_new();
+
+    /* sign the content stream */
+    hash_algo =
+	libbalsa_gpgme_sign(userid, filtered, sigstream, protocol, FALSE,
+			    parent, err);
+    if (hash_algo == GPGME_MD_NONE) {
+	g_object_unref(sigstream);
+	g_object_unref(filtered);
+	g_object_unref(stream);
+	return -1;
+    }
+
+    g_object_unref(filtered);
+    g_mime_stream_reset(sigstream);
+    g_mime_stream_reset(stream);
+
+    /* set the multipart/signed protocol and micalg */
+    content_type = g_mime_object_get_content_type(GMIME_OBJECT(mps));
+    if (protocol == GPGME_PROTOCOL_OpenPGP) {
+	gchar *micalg;
+
+	micalg =
+	    g_strdup_printf("PGP-%s", gpgme_hash_algo_name(hash_algo));
+	g_mime_content_type_set_parameter(content_type, "micalg", micalg);
+	g_free(micalg);
+	sig_type = "application/pgp-signature";
+    } else {
+	g_mime_content_type_set_parameter(content_type, "micalg",
+					  gpgme_hash_algo_name(hash_algo));
+	sig_type = "application/pkcs7-signature";
+    }
+    g_mime_content_type_set_parameter(content_type, "protocol", sig_type);
+    g_mime_multipart_set_boundary(GMIME_MULTIPART(mps), NULL);
+
+    /* construct the content part */
+    parser = g_mime_parser_new_with_stream(stream);
+    content = g_mime_parser_construct_part(parser);
+    g_object_unref(stream);
+    g_object_unref(parser);
+
+    /* construct the signature part */
+    content_type = g_mime_content_type_new_from_string(sig_type);
+    signature =
+	g_mime_part_new_with_type(content_type->type,
+				  content_type->subtype);
+    g_object_unref(content_type);
+
+    wrapper = g_mime_data_wrapper_new();
+    g_mime_data_wrapper_set_stream(wrapper, sigstream);
+    g_mime_part_set_content_object(signature, wrapper);
+    g_object_unref(sigstream);
+    g_object_unref(wrapper);
+
+    /* FIXME: temporary hack, this info should probably be set in
+     * the CipherContext class - maybe ::sign can take/output a
+     * GMimePart instead. */
+    if (protocol == GPGME_PROTOCOL_CMS) {
+	g_mime_part_set_content_encoding(signature,
+					 GMIME_CONTENT_ENCODING_BASE64);
+	g_mime_part_set_filename(signature, "smime.p7m");
+    }
+
+    /* save the content and signature parts */
+    /* FIXME: make sure there aren't any other parts?? */
+    g_mime_multipart_add(GMIME_MULTIPART(mps), content);
+    g_mime_multipart_add(GMIME_MULTIPART(mps), (GMimeObject *) signature);
+    g_object_unref(signature);
+    g_object_unref(content);
+
+    return 0;
+}
+
+
+GMimeGpgmeSigstat *
+g_mime_gpgme_mps_verify(GMimeMultipartSigned * mps, GError ** error)
+{
+    const gchar *protocol;
+    gpgme_protocol_t crypto_prot;
+    gchar *content_type;
+    GMimeObject *content;
+    GMimeObject *signature;
+    GMimeStream *stream;
+    GMimeStream *filtered_stream;
+    GMimeFilter *crlf_filter;
+    GMimeDataWrapper *wrapper;
+    GMimeStream *sigstream;
+    GMimeGpgmeSigstat *result;
+
+    g_return_val_if_fail(GMIME_IS_MULTIPART_SIGNED(mps), NULL);
+
+    if (g_mime_multipart_get_count((GMimeMultipart *) mps) < 2) {
+	g_set_error(error, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s",
+		    _
+		    ("Cannot verify multipart/signed part due to missing subparts."));
+	return NULL;
+    }
+
+    /* grab the protocol so we can configure the GpgME context */
+    protocol =
+	g_mime_object_get_content_type_parameter(GMIME_OBJECT(mps),
+						 "protocol");
+    if (protocol) {
+	if (g_ascii_strcasecmp("application/pgp-signature", protocol) == 0)
+	    crypto_prot = GPGME_PROTOCOL_OpenPGP;
+#if defined(HAVE_SMIME)
+	else if (g_ascii_strcasecmp
+		 ("application/pkcs7-signature", protocol) == 0
+		 || g_ascii_strcasecmp("application/x-pkcs7-signature",
+				       protocol) == 0)
+	    crypto_prot = GPGME_PROTOCOL_CMS;
+#endif
+	else
+	    crypto_prot = GPGME_PROTOCOL_UNKNOWN;
+    } else
+	crypto_prot = GPGME_PROTOCOL_UNKNOWN;
+
+    /* eject on unknown protocols */
+    if (crypto_prot == GPGME_PROTOCOL_UNKNOWN) {
+	g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_INV_VALUE,
+		    _("unsupported protocol '%s'"), protocol);
+	return NULL;
+    }
+
+    signature =
+	g_mime_multipart_get_part(GMIME_MULTIPART(mps),
+				  GMIME_MULTIPART_SIGNED_SIGNATURE);
+
+    /* make sure the protocol matches the signature content-type */
+    content_type = g_mime_content_type_to_string(signature->content_type);
+    if (g_ascii_strcasecmp(content_type, protocol) != 0) {
+	g_set_error(error, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s",
+		    _
+		    ("Cannot verify multipart/signed part: signature content-type does not match protocol."));
+	g_free(content_type);
+	return NULL;
+    }
+    g_free(content_type);
+
+    content =
+	g_mime_multipart_get_part(GMIME_MULTIPART(mps),
+				  GMIME_MULTIPART_SIGNED_CONTENT);
+
+    /* get the content stream */
+    stream = g_mime_stream_mem_new();
+    filtered_stream = g_mime_stream_filter_new(stream);
+
+    /* Note: see rfc2015 or rfc3156, section 5.1 */
+    crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE);
+    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
+			     crlf_filter);
+    g_object_unref(crlf_filter);
+
+    g_mime_object_write_to_stream(content, filtered_stream);
+    g_mime_stream_flush(filtered_stream);
+    g_object_unref(filtered_stream);
+    g_mime_stream_reset(stream);
+
+    /* get the signature stream */
+    wrapper = g_mime_part_get_content_object(GMIME_PART(signature));
+
+    /* FIXME: temporary hack for Balsa to support S/MIME,
+     * ::verify() should probably take a mime part so it can
+     * decode this itself if it needs to. */
+    if (crypto_prot == GPGME_PROTOCOL_CMS) {
+	sigstream = g_mime_stream_mem_new();
+	g_mime_data_wrapper_write_to_stream(wrapper, sigstream);
+    } else {
+	sigstream = g_mime_data_wrapper_get_stream(wrapper);
+    }
+
+    g_mime_stream_reset(sigstream);
+
+    /* verify the signature */
+    result =
+	libbalsa_gpgme_verify(stream, sigstream, crypto_prot, FALSE,
+			      error);
+    g_object_unref(stream);
+
+    return result;
+}
+
+
+int
+g_mime_gpgme_mpe_encrypt(GMimeMultipartEncrypted * mpe,
+			 GMimeObject * content, GPtrArray * recipients,
+			 gboolean trust_all, GtkWindow * parent,
+			 GError ** err)
+{
+    GMimeStream *filtered_stream;
+    GMimeStream *ciphertext;
+    GMimeStream *stream;
+    GMimePart *version_part;
+    GMimePart *encrypted_part;
+    GMimeContentType *content_type;
+    GMimeDataWrapper *wrapper;
+    GMimeFilter *crlf_filter;
+
+    g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), -1);
+    g_return_val_if_fail(GMIME_IS_OBJECT(content), -1);
+
+    /* get the cleartext */
+    stream = g_mime_stream_mem_new();
+    filtered_stream = g_mime_stream_filter_new(stream);
+
+    crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE);
+    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
+			     crlf_filter);
+    g_object_unref(crlf_filter);
+
+    g_mime_object_write_to_stream(content, filtered_stream);
+    g_mime_stream_flush(filtered_stream);
+    g_object_unref(filtered_stream);
+
+    /* reset the content stream */
+    g_mime_stream_reset(stream);
+
+    /* encrypt the content stream */
+    ciphertext = g_mime_stream_mem_new();
+    if (libbalsa_gpgme_encrypt
+	(recipients, NULL, stream, ciphertext, GPGME_PROTOCOL_OpenPGP,
+	 FALSE, trust_all, parent, err) == -1) {
+	g_object_unref(ciphertext);
+	g_object_unref(stream);
+	return -1;
+    }
+
+    g_object_unref(stream);
+    g_mime_stream_reset(ciphertext);
+
+    /* construct the version part */
+    content_type =
+	g_mime_content_type_new_from_string("application/pgp-encrypted");
+    version_part =
+	g_mime_part_new_with_type(content_type->type,
+				  content_type->subtype);
+    g_object_unref(content_type);
+
+    content_type =
+	g_mime_content_type_new_from_string("application/pgp-encrypted");
+    g_mime_object_set_content_type(GMIME_OBJECT(version_part),
+				   content_type);
+    g_mime_part_set_content_encoding(version_part,
+				     GMIME_CONTENT_ENCODING_7BIT);
+    stream =
+	g_mime_stream_mem_new_with_buffer("Version: 1\n",
+					  strlen("Version: 1\n"));
+    wrapper =
+	g_mime_data_wrapper_new_with_stream(stream,
+					    GMIME_CONTENT_ENCODING_7BIT);
+    g_mime_part_set_content_object(version_part, wrapper);
+    g_object_unref(wrapper);
+    g_object_unref(stream);
+
+#if !defined(HAVE_GMIME_2_6)
+    mpe->decrypted = content;
+    g_object_ref(content);
+#endif
+
+    /* construct the encrypted mime part */
+    encrypted_part =
+	g_mime_part_new_with_type("application", "octet-stream");
+    g_mime_part_set_content_encoding(encrypted_part,
+				     GMIME_CONTENT_ENCODING_7BIT);
+    wrapper =
+	g_mime_data_wrapper_new_with_stream(ciphertext,
+					    GMIME_CONTENT_ENCODING_7BIT);
+    g_mime_part_set_content_object(encrypted_part, wrapper);
+    g_object_unref(ciphertext);
+    g_object_unref(wrapper);
+
+    /* save the version and encrypted parts */
+    /* FIXME: make sure there aren't any other parts?? */
+    g_mime_multipart_add(GMIME_MULTIPART(mpe), GMIME_OBJECT(version_part));
+    g_mime_multipart_add(GMIME_MULTIPART(mpe),
+			 GMIME_OBJECT(encrypted_part));
+    g_object_unref(encrypted_part);
+    g_object_unref(version_part);
+
+    /* set the content-type params for this multipart/encrypted part */
+    g_mime_object_set_content_type_parameter(GMIME_OBJECT(mpe), "protocol",
+					     "application/pgp-encrypted");
+    g_mime_multipart_set_boundary(GMIME_MULTIPART(mpe), NULL);
+
+    return 0;
+}
+
+
+static GMimeStream *
+g_mime_data_wrapper_get_decoded_stream(GMimeDataWrapper * wrapper)
+{
+    GMimeStream *decoded_stream;
+    GMimeFilter *decoder;
+
+    g_mime_stream_reset(wrapper->stream);
+
+    switch (wrapper->encoding) {
+    case GMIME_CONTENT_ENCODING_BASE64:
+    case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
+    case GMIME_CONTENT_ENCODING_UUENCODE:
+	decoder = g_mime_filter_basic_new(wrapper->encoding, FALSE);
+	decoded_stream = g_mime_stream_filter_new(wrapper->stream);
+	g_mime_stream_filter_add(GMIME_STREAM_FILTER(decoded_stream),
+				 decoder);
+	g_object_unref(decoder);
+	break;
+    default:
+	decoded_stream = wrapper->stream;
+	g_object_ref(wrapper->stream);
+	break;
+    }
+
+    return decoded_stream;
+}
+
+
+GMimeObject *
+g_mime_gpgme_mpe_decrypt(GMimeMultipartEncrypted * mpe,
+			 GMimeGpgmeSigstat ** signature,
+			 GtkWindow * parent, GError ** err)
+{
+    GMimeObject *decrypted, *version, *encrypted;
+    GMimeStream *stream, *ciphertext;
+    GMimeStream *filtered_stream;
+    GMimeContentType *mime_type;
+    GMimeGpgmeSigstat *sigstat;
+    GMimeDataWrapper *wrapper;
+    GMimeFilter *crlf_filter;
+    GMimeParser *parser;
+    const char *protocol;
+    char *content_type;
+
+    g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), NULL);
+
+#if !defined(HAVE_GMIME_2_6)
+    if (mpe->decrypted) {
+	/* we seem to have already decrypted the part */
+	return mpe->decrypted;
+    }
+#endif
+
+    if (signature && *signature) {
+	g_object_unref(G_OBJECT(*signature));
+	*signature = NULL;
+    }
+
+    protocol =
+	g_mime_object_get_content_type_parameter(GMIME_OBJECT(mpe),
+						 "protocol");
+
+    /* make sure the protocol is present and matches the cipher encrypt protocol */
+    if (!protocol
+	|| g_ascii_strcasecmp("application/pgp-encrypted",
+			      protocol) != 0) {
+	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
+		    _
+		    ("Cannot decrypt multipart/encrypted part: unsupported encryption protocol '%s'."),
+		    protocol ? protocol : _("(none)"));
+	return NULL;
+    }
+
+    version =
+	g_mime_multipart_get_part(GMIME_MULTIPART(mpe),
+				  GMIME_MULTIPART_ENCRYPTED_VERSION);
+
+    /* make sure the protocol matches the version part's content-type */
+    content_type = g_mime_content_type_to_string(version->content_type);
+    if (g_ascii_strcasecmp(content_type, protocol) != 0) {
+	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s",
+		    _
+		    ("Cannot decrypt multipart/encrypted part: content-type does not match protocol."));
+	g_free(content_type);
+	return NULL;
+    }
+    g_free(content_type);
+
+    /* get the encrypted part and check that it is of type application/octet-stream */
+    encrypted =
+	g_mime_multipart_get_part(GMIME_MULTIPART(mpe),
+				  GMIME_MULTIPART_ENCRYPTED_CONTENT);
+    mime_type = g_mime_object_get_content_type(encrypted);
+    if (!g_mime_content_type_is_type
+	(mime_type, "application", "octet-stream")) {
+	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s",
+		    _
+		    ("Cannot decrypt multipart/encrypted part: unexpected content type"));
+	return NULL;
+    }
+
+    /* get the ciphertext stream */
+    wrapper = g_mime_part_get_content_object(GMIME_PART(encrypted));
+    ciphertext = g_mime_data_wrapper_get_decoded_stream(wrapper);
+    g_mime_stream_reset(ciphertext);
+
+    stream = g_mime_stream_mem_new();
+    filtered_stream = g_mime_stream_filter_new(stream);
+    crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE);
+    g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream),
+			     crlf_filter);
+    g_object_unref(crlf_filter);
+
+    /* get the cleartext */
+    sigstat =
+	libbalsa_gpgme_decrypt(ciphertext, filtered_stream,
+			       GPGME_PROTOCOL_OpenPGP, parent, err);
+    if (!sigstat) {
+	g_object_unref(filtered_stream);
+	g_object_unref(ciphertext);
+	g_object_unref(stream);
+	return NULL;
+    }
+
+    g_mime_stream_flush(filtered_stream);
+    g_object_unref(filtered_stream);
+    g_object_unref(ciphertext);
+
+    g_mime_stream_reset(stream);
+    parser = g_mime_parser_new();
+    g_mime_parser_init_with_stream(parser, stream);
+    g_object_unref(stream);
+
+    decrypted = g_mime_parser_construct_part(parser);
+    g_object_unref(parser);
+
+    if (!decrypted) {
+	g_set_error(err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s",
+		    _
+		    ("Cannot decrypt multipart/encrypted part: failed to parse decrypted content"));
+	g_object_unref(G_OBJECT(sigstat));
+	return NULL;
+    }
+
+
+    /* cache the decrypted part */
+#if !defined(HAVE_GMIME_2_6)
+    mpe->decrypted = decrypted;
+#endif
+    if (signature) {
+	if (sigstat->status != GPG_ERR_NOT_SIGNED)
+	    *signature = sigstat;
+	else
+	    g_object_unref(G_OBJECT(sigstat));
+    }
+
+    return decrypted;
+}
diff --git a/libbalsa/gmime-multipart-crypt.h b/libbalsa/gmime-multipart-crypt.h
new file mode 100644
index 0000000..f7cc428
--- /dev/null
+++ b/libbalsa/gmime-multipart-crypt.h
@@ -0,0 +1,69 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * gmime/gpgme implementation for multipart/signed and multipart/encrypted
+ * Copyright (C) 2011 Albrecht Dreà <albrecht dress arcor de>
+ *
+ * The functions in this module were copied from the original GMime
+ * implementation of multipart/signed and multipart/encrypted parts.
+ * However, instead of using the complex GMime crypto contexts (which have
+ * a varying API over the different versions), this module directly calls
+ * the GpgME backend functions implemented in libbalsa-gpgme.[hc].
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option) 
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+ * GNU General Public License for more details.
+ *  
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
+ * 02111-1307, USA.
+ */
+
+#ifndef __GMIME_MULTIPART_CRYPT_H__
+#define __GMIME_MULTIPART_CRYPT_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gmime/gmime.h>
+#include <gpgme.h>
+#include "gmime-gpgme-signature.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#ifdef MAKE_EMACS_HAPPY
+}
+#endif
+#endif				/* __cplusplus */
+
+
+GMimeGpgmeSigstat *g_mime_gpgme_mps_verify(GMimeMultipartSigned * mps,
+					   GError ** error);
+int g_mime_gpgme_mps_sign(GMimeMultipartSigned * mps,
+			  GMimeObject * content, const gchar * userid,
+			  gpgme_protocol_t protocol, GtkWindow * parent,
+			  GError ** err);
+int g_mime_gpgme_mpe_encrypt(GMimeMultipartEncrypted * mpe,
+			     GMimeObject * content, GPtrArray * recipients,
+			     gboolean trust_all, GtkWindow * parent,
+			     GError ** err);
+GMimeObject *g_mime_gpgme_mpe_decrypt(GMimeMultipartEncrypted * mpe,
+				      GMimeGpgmeSigstat ** signature,
+				      GtkWindow * parent, GError ** err);
+
+
+#ifdef __cplusplus
+}
+#endif				/* __cplusplus */
+
+#endif				/* __GMIME_MULTIPART_CRYPT_H__ */
diff --git a/libbalsa/gmime-part-rfc2440.c b/libbalsa/gmime-part-rfc2440.c
index e79c4cb..4c032c6 100644
--- a/libbalsa/gmime-part-rfc2440.c
+++ b/libbalsa/gmime-part-rfc2440.c
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /*
- * gmime/gpgme glue layer library
- * Copyright (C) 2004 Albrecht Dreß<albrecht dress arcor de>
+ * gmime/gpgme implementation for RFC2440 parts
+ * Copyright (C) 2004-2011 Albrecht Dreà <albrecht dress arcor de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,21 +20,35 @@
  */
 
 #if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
-# include "config.h"
+#include "config.h"
 #endif                          /* HAVE_CONFIG_H */
-#include "gmime-part-rfc2440.h"
 
 #include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
 #include <gmime/gmime.h>
+#include "libbalsa-gpgme.h"
+#include "gmime-part-rfc2440.h"
 
 
 #define RFC2440_BUF_LEN    4096
 
+
+/** \brief Check for a part's RFC 2440 protection
+ *
+ * \param part GMime part which shall be inspected.
+ * \return The OpenPGP (RFC 2440) protection of the part.
+ *
+ * Check if the passed part is RFC 2440 signed or encrypted by looking for
+ * the "magic" strings defined there.  Note that parts which include extra
+ * data before the beginning or after the end of signed or encryped matter
+ * are always classified as GMIME_PART_RFC2440_NONE.
+ */
 GMimePartRfc2440Mode
 g_mime_part_check_rfc2440(GMimePart * part)
 {
-    GMimeDataWrapper * wrapper;
-    GMimeStream * stream;
+    GMimeDataWrapper *wrapper;
+    GMimeStream *stream;
     ssize_t slen;
     gchar buf[RFC2440_BUF_LEN];
     GMimePartRfc2440Mode retval = GMIME_PART_RFC2440_NONE;
@@ -58,7 +72,7 @@ g_mime_part_check_rfc2440(GMimePart * part)
 	    strstr(buf, "-----END PGP MESSAGE-----"))
 	    retval = GMIME_PART_RFC2440_ENCRYPTED;
 	else if (!strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34)) {
-	    gchar * p1, * p2;
+	    gchar *p1, *p2;
 
 	    p1 = strstr(buf, "-----BEGIN PGP SIGNATURE-----");
 	    p2 = strstr(buf, "-----END PGP SIGNATURE-----");
@@ -68,14 +82,15 @@ g_mime_part_check_rfc2440(GMimePart * part)
     } else {
 	/* check if the beginning of the stream matches */
 	g_mime_stream_read(stream, buf, 34);
-	g_mime_stream_seek(stream, 1 - RFC2440_BUF_LEN,  GMIME_STREAM_SEEK_END);
+	g_mime_stream_seek(stream, 1 - RFC2440_BUF_LEN,
+			   GMIME_STREAM_SEEK_END);
 	if (!strncmp(buf, "-----BEGIN PGP MESSAGE-----", 27)) {
 	    g_mime_stream_read(stream, buf, RFC2440_BUF_LEN - 1);
 	    buf[RFC2440_BUF_LEN - 1] = '\0';
 	    if (strstr(buf, "-----END PGP MESSAGE-----"))
 		retval = GMIME_PART_RFC2440_ENCRYPTED;
 	} else if (!strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34)) {
-	    gchar * p1, * p2;
+	    gchar *p1, *p2;
 
 	    g_mime_stream_read(stream, buf, RFC2440_BUF_LEN - 1);
 	    buf[RFC2440_BUF_LEN - 1] = '\0';
@@ -90,20 +105,30 @@ g_mime_part_check_rfc2440(GMimePart * part)
 }
 
 
-/*
- * RFC2440 sign, encrypt or sign and encrypt a gmime part using the
- * gmime gpgme context ctx. If sign_userid is not NULL, part will be
- * signed. If recipients is not NULL, encrypt part for recipients. If
- * both are not null, part will be first signed and then
+/** \brief RFC 2440 sign and/or encrypt a GMime part
+ *
+ * \param part GMime part which shall be signed and/or encrypted.
+ * \param sign_userid User ID of the signer, or NULL fo no signature.
+ * \param recipients Array of User ID for which the matter shall be
+ *        encrypted using their public keys, or NULL for no encryption.
+ * \param trust_all_keys TRUE if all low-truct keys shall be accepted for
+ *        encryption.
+ * \param parent Parent window to be passed to the callback functions.
+ * \param error Filled with error information on error.
+ * \return 0 on success, or -1 on error.
+ *
+ * RFC2440 sign, encrypt or sign and encrypt a gmime part.  If sign_userid
+ * is not NULL, part will be signed.  If recipients is not NULL, encrypt
+ * part for recipients.  If both are not null, part will be both signed and
  * encrypted. Returns 0 on success or -1 on fail. If any operation
  * failed, an exception will be set on err to provide more
  * information.
  */
 int
-g_mime_part_rfc2440_sign_encrypt(GMimePart * part,
-				 GMimeGpgmeContext * ctx,
+g_mime_part_rfc2440_sign_encrypt(GMimePart * part, const char *sign_userid,
 				 GPtrArray * recipients,
-				 const char *sign_userid, GError ** err)
+				 gboolean trust_all, GtkWindow * parent,
+				 GError ** err)
 {
     GMimeDataWrapper *wrapper;
     GMimeStream *stream, *cipherstream;
@@ -111,14 +136,6 @@ g_mime_part_rfc2440_sign_encrypt(GMimePart * part,
     gint result;
 
     g_return_val_if_fail(GMIME_IS_PART(part), -1);
-    g_return_val_if_fail(GMIME_IS_GPGME_CONTEXT(ctx), -1);
-#ifndef HAVE_GMIME_2_5_7
-    g_return_val_if_fail(GMIME_CIPHER_CONTEXT(ctx)->sign_protocol != NULL,
-			 -1);
-#else /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail(g_mime_crypto_context_get_signature_protocol
-                         (GMIME_CRYPTO_CONTEXT(ctx)) != NULL, -1);
-#endif /* HAVE_GMIME_2_5_7 */
     g_return_val_if_fail(recipients != NULL || sign_userid != NULL, -1);
 
     /* get the raw content */
@@ -133,43 +150,31 @@ g_mime_part_rfc2440_sign_encrypt(GMimePart * part,
     g_mime_stream_mem_set_owner(GMIME_STREAM_MEM(cipherstream), TRUE);
 
     /* do the crypto operation */
-    ctx->singlepart_mode = TRUE;
-    if (recipients == NULL)
-	result =
-#ifndef HAVE_GMIME_2_5_7
-	    g_mime_cipher_context_sign(GMIME_CIPHER_CONTEXT(ctx), sign_userid,
-			       GMIME_CIPHER_HASH_DEFAULT, stream,
-			       cipherstream, err);
-#else /* HAVE_GMIME_2_5_7 */
-	    g_mime_crypto_context_sign(GMIME_CRYPTO_CONTEXT(ctx), sign_userid,
-			       GMIME_CIPHER_ALGO_DEFAULT, stream,
-			       cipherstream, err);
-#endif /* HAVE_GMIME_2_5_7 */
+    if (recipients == NULL) {
+	if (libbalsa_gpgme_sign
+	    (sign_userid, stream, cipherstream, GPGME_PROTOCOL_OpenPGP,
+	     TRUE, parent, err) == GPGME_MD_NONE)
+	    result = -1;
     else
+	    result = 0;
+    } else
 	result =
-#ifndef HAVE_GMIME_2_5_7
-	    g_mime_cipher_context_encrypt(GMIME_CIPHER_CONTEXT(ctx),
-				  sign_userid != NULL, sign_userid,
-				  recipients, stream, cipherstream, err);
-#else /* HAVE_GMIME_2_5_7 */
-	    g_mime_crypto_context_encrypt(GMIME_CRYPTO_CONTEXT(ctx),
-				  sign_userid != NULL, sign_userid,
-                                  GMIME_CIPHER_ALGO_DEFAULT,
-				  recipients, stream, cipherstream, err);
-#endif /* HAVE_GMIME_2_5_7 */
+	    libbalsa_gpgme_encrypt(recipients, sign_userid, stream,
+				   cipherstream, GPGME_PROTOCOL_OpenPGP,
+				   TRUE, trust_all, parent, err);
     if (result == -1) {
 	g_object_unref(cipherstream);
 	return -1;
     }
 
-    /* add the headers to encrypted ascii armor output: as there is no "insert"
-     * method for the byte array, first remove the leading "BEGIN PGP MESSAGE"
-     * (27 chars) and prepend it again... */
+    /* add the headers to encrypted ascii armor output: as there is no
+     * "insert" method for the byte array, first remove the leading "BEGIN
+     * PGP MESSAGE" (27 chars) and prepend it again... */
     if (recipients && g_mime_object_get_content_type(GMIME_OBJECT(part))) {
 	const gchar *charset =
 	    g_mime_object_get_content_type_parameter(GMIME_OBJECT(part),
 						     "charset");
-	gchar * rfc2440header;
+	gchar *rfc2440header;
 	
 	rfc2440header =
 	    g_strdup_printf("-----BEGIN PGP MESSAGE-----\nCharset: %s\n"
@@ -189,16 +194,19 @@ g_mime_part_rfc2440_sign_encrypt(GMimePart * part,
     /*
      * Paranoia: set the encoding of a signed part to quoted-printable (not
      * requested by RFC2440, but it's safer...). If we encrypted use 7-bit
-     * and set the charset to us-ascii instead, as gpg added it's own armor.
+     * and set the charset to us-ascii instead, as gpg added it's own
+     * armor.
      */
     if (recipients == NULL) {
-	if (g_mime_part_get_content_encoding(part) != GMIME_CONTENT_ENCODING_BASE64)
+	if (g_mime_part_get_content_encoding(part) !=
+	    GMIME_CONTENT_ENCODING_BASE64)
 	    g_mime_part_set_content_encoding(part,
 				     GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE);
 	g_mime_data_wrapper_set_encoding(wrapper,
 					 GMIME_CONTENT_ENCODING_DEFAULT);
     } else {
-	g_mime_part_set_content_encoding(part, GMIME_CONTENT_ENCODING_7BIT);
+	g_mime_part_set_content_encoding(part,
+					 GMIME_CONTENT_ENCODING_7BIT);
 	g_mime_data_wrapper_set_encoding(wrapper,
 					 GMIME_CONTENT_ENCODING_7BIT);
 	g_mime_object_set_content_type_parameter(GMIME_OBJECT(part),
@@ -213,38 +221,27 @@ g_mime_part_rfc2440_sign_encrypt(GMimePart * part,
 }
 
 
-/*
- * Verify the signature of the RFC 2440 signed part using the gpgme
- * context ctx and return the validity as determined by the crypto
- * routines or NULL on error. In the latter case, an exception will be
- * set on err to provide more information. Upon success, the content
- * of part is replaced by the verified output of the crypto engine.
+/* \brief Verify a RFC 2440 signed part
+ *
+ * \param part GMime part which shall be verified.
+ * \param error Filled with error information on error.
+ * \return A new signature status object on success, or NULL on error.
+ *
+ * Verify the signature of the RFC 2440 signed part and return the
+ * signature status as determined by the crypto routines or NULL on error.
+ * In the latter case, an exception will be set on err to provide more
+ * information.  Upon success, the content of part is replaced by the
+ * verified output of the crypto engine.
  */
-#ifndef HAVE_GMIME_2_5_7
-GMimeSignatureValidity *
-#else /* HAVE_GMIME_2_5_7 */
-GMimeSignatureList *
-#endif /* HAVE_GMIME_2_5_7 */
-g_mime_part_rfc2440_verify(GMimePart * part,
-			   GMimeGpgmeContext * ctx, GError ** err)
+GMimeGpgmeSigstat *
+g_mime_part_rfc2440_verify(GMimePart * part, GError ** err)
 {
-    GMimeStream *stream, *plainstream;
-    GMimeDataWrapper * wrapper;
-#ifndef HAVE_GMIME_2_5_7
-    GMimeSignatureValidity *valid;
-#else /* HAVE_GMIME_2_5_7 */
-    GMimeSignatureList *list;
-#endif /* HAVE_GMIME_2_5_7 */
+    GMimeStream *stream;
+    GMimeStream *plainstream;
+    GMimeDataWrapper *wrapper;
+    GMimeGpgmeSigstat *result;
 
     g_return_val_if_fail(GMIME_IS_PART(part), NULL);
-    g_return_val_if_fail(GMIME_IS_GPGME_CONTEXT(ctx), NULL);
-#ifndef HAVE_GMIME_2_5_7
-    g_return_val_if_fail(GMIME_CIPHER_CONTEXT(ctx)->sign_protocol != NULL,
-			 NULL);
-#else /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail(g_mime_crypto_context_get_signature_protocol
-                         (GMIME_CRYPTO_CONTEXT(ctx)) != NULL, NULL);
-#endif /* HAVE_GMIME_2_5_7 */
 
     /* get the raw content */
     wrapper = g_mime_part_get_content_object(GMIME_PART(part));
@@ -257,26 +254,12 @@ g_mime_part_rfc2440_verify(GMimePart * part,
     plainstream = g_mime_stream_mem_new();
 
     /* verify the signature */
-    ctx->singlepart_mode = TRUE;
-#ifndef HAVE_GMIME_2_5_7
-    valid =
-	g_mime_cipher_context_verify(GMIME_CIPHER_CONTEXT(ctx),
-			     GMIME_CIPHER_HASH_DEFAULT, stream,
-			     plainstream, err);
-#else /* HAVE_GMIME_2_5_7 */
-    list =
-	g_mime_crypto_context_verify(GMIME_CRYPTO_CONTEXT(ctx),
-			     GMIME_CIPHER_ALGO_DEFAULT, stream,
-			     plainstream, err);
-#endif /* HAVE_GMIME_2_5_7 */
+    result =
+	libbalsa_gpgme_verify(stream, plainstream, GPGME_PROTOCOL_OpenPGP,
+			      TRUE, err);
 
     /* upon success, replace the signed content by the checked one */
-#ifndef HAVE_GMIME_2_5_7
-    if (valid)
-#else /* HAVE_GMIME_2_5_7 */
-    if (list)
-#endif /* HAVE_GMIME_2_5_7 */
-    {
+    if (result) {
 	GMimeDataWrapper *wrapper = g_mime_data_wrapper_new();
 
 	g_mime_data_wrapper_set_stream(wrapper, plainstream);
@@ -285,49 +268,36 @@ g_mime_part_rfc2440_verify(GMimePart * part,
     }
     g_object_unref(plainstream);
 
-#ifndef HAVE_GMIME_2_5_7
-    return valid;
-#else /* HAVE_GMIME_2_5_7 */
-    return list;
-#endif /* HAVE_GMIME_2_5_7 */
+    return result;
 }
 
 
-/*
- * Decrypt the RFC 2440 encrypted part using the gmime gpgme context
- * ctx and return 0 on success or -1 for fail. In the latter case, an
- * exception will be set on err to provide more information. Upon
+/* \brief Decrypt a RFC 2440 encrypted part
+ *
+ * \param part GMime part which shall be verified.
+ * \param parent Parent window to be passed to the passphrase callback
+ *        function.
+ * \param error Filled with error information on error.
+ * \return A new signature status object on success, or NULL on error.
+ *
+ * Decrypt the RFC 2440 encrypted part and return the signature status as
+ * determined by the crypto routines or NULL on error.  In the latter case,
+ * an exception will be set on err to provide more information.  Upon
  * success, the content of part is replaced by the decrypted output of
  * the crypto engine. If the input was also signed, the signature is
- * verified and the result is placed in ctx by the underlying gpgme
- * context.
+ * verified.
  */
-#ifndef HAVE_GMIME_2_5_7
-GMimeSignatureValidity *
-#else /* HAVE_GMIME_2_5_7 */
-GMimeDecryptResult *
-#endif /* HAVE_GMIME_2_5_7 */
-g_mime_part_rfc2440_decrypt(GMimePart * part,
-			    GMimeGpgmeContext * ctx, GError ** err)
+GMimeGpgmeSigstat *
+g_mime_part_rfc2440_decrypt(GMimePart * part, GtkWindow * parent,
+			    GError ** err)
 {
-    GMimeStream *stream, *plainstream;
-    GMimeDataWrapper * wrapper;
-#ifndef HAVE_GMIME_2_5_7
-    GMimeSignatureValidity *result;
-#else /* HAVE_GMIME_2_5_7 */
-    GMimeDecryptResult *result;
-#endif /* HAVE_GMIME_2_5_7 */
+    GMimeStream *stream;
+    GMimeStream *plainstream;
+    GMimeDataWrapper *wrapper;
+    GMimeGpgmeSigstat *result;
     gchar *headbuf = g_malloc0(1024);
 
     g_return_val_if_fail(GMIME_IS_PART(part), NULL);
-    g_return_val_if_fail(GMIME_IS_GPGME_CONTEXT(ctx), NULL);
-#ifndef HAVE_GMIME_2_5_7
-    g_return_val_if_fail(GMIME_CIPHER_CONTEXT(ctx)->encrypt_protocol !=
-			 NULL, NULL);
-#else /* HAVE_GMIME_2_5_7 */
-    g_return_val_if_fail(g_mime_crypto_context_get_encryption_protocol
-                         (GMIME_CRYPTO_CONTEXT(ctx)) != NULL, NULL);
-#endif /* HAVE_GMIME_2_5_7 */
 
     /* get the raw content */
     wrapper = g_mime_part_get_content_object(part);
@@ -344,13 +314,8 @@ g_mime_part_rfc2440_decrypt(GMimePart * part,
 
     /* decrypt and (if possible) verify the input */
     result =
-#ifndef HAVE_GMIME_2_5_7
-	g_mime_cipher_context_decrypt(GMIME_CIPHER_CONTEXT(ctx), stream,
-			      plainstream, err);
-#else /* HAVE_GMIME_2_5_7 */
-	g_mime_crypto_context_decrypt(GMIME_CRYPTO_CONTEXT(ctx), stream,
-                                      plainstream, err);
-#endif /* HAVE_GMIME_2_5_7 */
+	libbalsa_gpgme_decrypt(stream, plainstream, GPGME_PROTOCOL_OpenPGP,
+			       parent, err);
 
     if (result != NULL) {
 	GMimeStream *filter_stream;
@@ -361,7 +326,8 @@ g_mime_part_rfc2440_decrypt(GMimePart * part,
 	/* strip crlf off encrypted stuff coming from Winbloze crap */
 	filter_stream = g_mime_stream_filter_new(plainstream);
 	filter = g_mime_filter_crlf_new(FALSE, FALSE);
-	g_mime_stream_filter_add(GMIME_STREAM_FILTER(filter_stream), filter);
+	g_mime_stream_filter_add(GMIME_STREAM_FILTER(filter_stream),
+				 filter);
 	g_object_unref(filter);
 
 	/* replace the old contents by the decrypted stuff */
@@ -372,14 +338,15 @@ g_mime_part_rfc2440_decrypt(GMimePart * part,
 	g_mime_stream_write_to_stream(filter_stream, out_stream);
 	g_object_unref(filter_stream);
 
-	g_mime_part_set_content_encoding(part, GMIME_CONTENT_ENCODING_8BIT);
+	g_mime_part_set_content_encoding(part,
+					 GMIME_CONTENT_ENCODING_8BIT);
 
 	/*
- 	 * Set the charset of the decrypted content to the RFC 2440 "Charset:"
- 	 * header. If it is not present, RFC 2440 defines that the contents
- 	 * should be utf-8, but real-life applications (e.g. pgp4pine) tend to
- 	 * use "some" charset, so "unknown-8bit" is a safe choice in this case
- 	 * and if no other charset is given.
+	 * Set the charset of the decrypted content to the RFC 2440
+	 * "Charset:" header.  If it is not present, RFC 2440 defines that
+	 * the contents should be utf-8, but real-life applications (e.g.
+	 * pgp4pine) tend to use "some" charset, so "unknown-8bit" is a
+	 * safe choice in this case and if no other charset is given.
 	 */
 	if (g_mime_object_get_content_type(GMIME_OBJECT(part))) {
  	    gchar *up_headbuf = g_ascii_strup(headbuf, -1);
@@ -393,13 +360,17 @@ g_mime_part_rfc2440_decrypt(GMimePart * part,
  		while (*line_end > ' ')
  		    line_end++;
  		*line_end = '\0';
-		g_mime_object_set_content_type_parameter(GMIME_OBJECT(part),
-							 "charset", p);
+		g_mime_object_set_content_type_parameter(GMIME_OBJECT
+							 (part), "charset",
+							 p);
  	    } else {
-		if (!g_ascii_strcasecmp("us-ascii",
-			 g_mime_object_get_content_type_parameter(GMIME_OBJECT(part),
+		if (!g_ascii_strcasecmp
+		    ("us-ascii",
+		     g_mime_object_get_content_type_parameter(GMIME_OBJECT
+							      (part),
 								  "charset")))
-		    g_mime_object_set_content_type_parameter(GMIME_OBJECT(part),
+		    g_mime_object_set_content_type_parameter(GMIME_OBJECT
+							     (part),
 							     "charset",
 							     "unknown-8bit");
 	    }
diff --git a/libbalsa/gmime-part-rfc2440.h b/libbalsa/gmime-part-rfc2440.h
index cc1901a..a757031 100644
--- a/libbalsa/gmime-part-rfc2440.h
+++ b/libbalsa/gmime-part-rfc2440.h
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /*
- * gmime/gpgme glue layer library
- * Copyright (C) 2004 Albrecht Dreß<albrecht dress arcor de>
+ * gmime/gpgme implementation for RFC2440 parts
+ * Copyright (C) 2004-2011 Albrecht Dreà <albrecht dress arcor de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,19 +23,18 @@
 #define __GMIME_PART_RFC2440_H__
 
 
+#include <glib.h>
+#include <gtk/gtk.h>
 #include <gmime/gmime.h>
-#include "gmime-gpgme-context.h"
 
 
 #ifdef __cplusplus
 extern "C" {
 
-#  ifdef MAKE_EMACS_HAPPY
+#ifdef MAKE_EMACS_HAPPY
 }
-#  endif
+#endif
 #endif				/* __cplusplus */
-
-
 typedef enum _GMimePartRfc2440Mode GMimePartRfc2440Mode;
 enum _GMimePartRfc2440Mode { 
     GMIME_PART_RFC2440_NONE,
@@ -49,25 +48,15 @@ GMimePartRfc2440Mode g_mime_part_check_rfc2440(GMimePart * part);
 
 /* crypto routines */
 int g_mime_part_rfc2440_sign_encrypt(GMimePart * part,
-				     GMimeGpgmeContext * ctx,
-				     GPtrArray * recipients,
 				     const char *sign_userid,
+				     GPtrArray * recipients,
+				     gboolean trust_all,
+				     GtkWindow * parent, GError ** err);
+GMimeGpgmeSigstat *g_mime_part_rfc2440_verify(GMimePart * part,
 				     GError ** err);
-#ifndef HAVE_GMIME_2_5_7
-GMimeSignatureValidity *g_mime_part_rfc2440_verify(GMimePart * part,
-						   GMimeGpgmeContext * ctx,
-						   GError ** err);
-GMimeSignatureValidity *g_mime_part_rfc2440_decrypt(GMimePart * part,
-                                                    GMimeGpgmeContext *
-                                                    ctx, GError ** err);
-#else /* HAVE_GMIME_2_5_7 */
-GMimeSignatureList *g_mime_part_rfc2440_verify(GMimePart * part,
-                                               GMimeGpgmeContext * ctx,
-                                               GError ** err);
-GMimeDecryptResult *g_mime_part_rfc2440_decrypt(GMimePart * part,
-                                                GMimeGpgmeContext * ctx,
+GMimeGpgmeSigstat *g_mime_part_rfc2440_decrypt(GMimePart * part,
+					       GtkWindow * parent,
                                                 GError ** err);
-#endif /* HAVE_GMIME_2_5_7 */
 
 #ifdef __cplusplus
 }
diff --git a/libbalsa/libbalsa-gpgme-cb.c b/libbalsa/libbalsa-gpgme-cb.c
new file mode 100644
index 0000000..a2eba03
--- /dev/null
+++ b/libbalsa/libbalsa-gpgme-cb.c
@@ -0,0 +1,428 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * gpgme standard callback functions for balsa
+ * Copyright (C) 2011 Albrecht Dreà <albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if HAVE_MACOSX_DESKTOP
+#include "macosx-helpers.h"
+#endif
+
+#ifdef BALSA_USE_THREADS
+#include <pthread.h>
+#include "misc.h"
+#endif
+
+#include <gpgme.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include "rfc3156.h"
+#include "libbalsa-gpgme-cb.h"
+
+
+/* stuff to get a key fingerprint from a selection list */
+enum {
+    GPG_KEY_USER_ID_COLUMN = 0,
+    GPG_KEY_ID_COLUMN,
+    GPG_KEY_LENGTH_COLUMN,
+    GPG_KEY_VALIDITY_COLUMN,
+    GPG_KEY_PTR_COLUMN,
+    GPG_KEY_NUM_COLUMNS
+};
+
+#ifdef BALSA_USE_THREADS
+/* FIXME: is this really necessary? */
+typedef struct {
+    pthread_cond_t cond;
+    const gchar *uid_hint;
+    const gchar *passphrase_info;
+    gint was_bad;
+    GtkWindow *parent;
+    gchar *res;
+} ask_passphrase_data_t;
+#endif
+
+
+static void key_selection_changed_cb(GtkTreeSelection * selection,
+				     gpgme_key_t * key);
+static gchar *get_passphrase_real(const gchar * uid_hint,
+				  const gchar * passphrase_info,
+				  int prev_was_bad, GtkWindow * parent);
+
+#ifdef BALSA_USE_THREADS
+static gboolean get_passphrase_idle(gpointer data);
+#endif
+
+
+gpgme_error_t
+lb_gpgme_passphrase(void *hook, const gchar * uid_hint,
+		    const gchar * passphrase_info, int prev_was_bad,
+		    int fd)
+{
+    int foo, bar;
+    gchar *passwd;
+    gchar *p;
+    GtkWindow *parent;
+
+    if (hook && GTK_IS_WINDOW(hook))
+	parent = (GtkWindow *) hook;
+    else
+	parent = NULL;
+
+#ifdef BALSA_USE_THREADS
+    if (!libbalsa_am_i_subthread())
+	passwd =
+	    get_passphrase_real(uid_hint, passphrase_info, prev_was_bad,
+				parent);
+    else {
+	static pthread_mutex_t get_passphrase_lock =
+	    PTHREAD_MUTEX_INITIALIZER;
+	ask_passphrase_data_t apd;
+
+	pthread_mutex_lock(&get_passphrase_lock);
+	pthread_cond_init(&apd.cond, NULL);
+	apd.uid_hint = uid_hint;
+	apd.was_bad = prev_was_bad;
+	apd.passphrase_info = passphrase_info;
+	apd.parent = parent;
+	g_idle_add(get_passphrase_idle, &apd);
+	pthread_cond_wait(&apd.cond, &get_passphrase_lock);
+	pthread_cond_destroy(&apd.cond);
+	pthread_mutex_unlock(&get_passphrase_lock);
+	passwd = apd.res;
+    }
+#else
+    passwd = get_passphrase_real(context, uid_hint, prev_was_bad);
+#endif				/* BALSA_USE_THREADS */
+
+    if (!passwd) {
+	foo = write(fd, "\n", 1);
+	return foo > 0 ? GPG_ERR_CANCELED : GPG_ERR_EIO;
+    }
+
+    /* send the passphrase and erase the string */
+    foo = write(fd, passwd, strlen(passwd));
+    for (p = passwd; *p; p++)
+	*p = random();
+    g_free(passwd);
+    bar = write(fd, "\n", 1);
+    return foo > 0 && bar > 0 ? GPG_ERR_NO_ERROR : GPG_ERR_EIO;
+}
+
+
+gpgme_key_t
+lb_gpgme_select_key(const gchar * user_name, gboolean secret, GList * keys,
+		    gpgme_protocol_t protocol, GtkWindow * parent)
+{
+    static const gchar *col_titles[] =
+	{ N_("User ID"), N_("Key ID"), N_("Length"), N_("Validity") };
+    GtkWidget *dialog;
+    GtkWidget *vbox;
+    GtkWidget *label;
+    GtkWidget *scrolled_window;
+    GtkWidget *tree_view;
+    GtkTreeStore *model;
+    GtkTreeSelection *selection;
+    GtkTreeIter iter;
+    gint i, last_col;
+    gchar *prompt;
+    gchar *upcase_name;
+    gpgme_key_t use_key = NULL;
+
+    /* FIXME: create dialog according to the Gnome HIG */
+    dialog = gtk_dialog_new_with_buttons(_("Select key"),
+					 parent,
+					 GTK_DIALOG_DESTROY_WITH_PARENT,
+					 GTK_STOCK_OK, GTK_RESPONSE_OK,
+					 GTK_STOCK_CANCEL,
+					 GTK_RESPONSE_CANCEL, NULL);
+#if HAVE_MACOSX_DESKTOP
+    libbalsa_macosx_menu_for_parent(dialog, parent);
+#endif
+    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
+    gtk_container_add(GTK_CONTAINER
+		      (gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
+		      vbox);
+    gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
+    if (secret)
+	prompt =
+	    g_strdup_printf(_("Select the private key for the signer %s"),
+			    user_name);
+    else
+	prompt = g_strdup_printf(_
+				 ("Select the public key for the recipient %s"),
+				 user_name);
+    label = gtk_label_new(prompt);
+    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+    g_free(prompt);
+    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
+
+    scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW
+					(scrolled_window),
+					GTK_SHADOW_ETCHED_IN);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+				   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+    gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
+
+    model = gtk_tree_store_new(GPG_KEY_NUM_COLUMNS, G_TYPE_STRING,	/* user ID */
+			       G_TYPE_STRING,	/* key ID */
+			       G_TYPE_INT,	/* length */
+			       G_TYPE_STRING,	/* validity (gpg encrypt only) */
+			       G_TYPE_POINTER);	/* key */
+
+    tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
+    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
+    gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+    g_signal_connect(G_OBJECT(selection), "changed",
+		     G_CALLBACK(key_selection_changed_cb), &use_key);
+
+    /* add the keys */
+    upcase_name = g_ascii_strup(user_name, -1);
+    while (keys) {
+	gpgme_key_t key = (gpgme_key_t) keys->data;
+	gpgme_subkey_t subkey = key->subkeys;
+	gpgme_user_id_t uid = key->uids;
+	gchar *uid_info = NULL;
+	gboolean uid_found;
+
+	/* find the relevant subkey */
+	while (subkey && ((secret && !subkey->can_sign) ||
+			  (!secret && !subkey->can_encrypt)))
+	    subkey = subkey->next;
+
+	/* find the relevant uid */
+	uid_found = FALSE;
+	while (uid && !uid_found) {
+	    g_free(uid_info);
+	    uid_info = libbalsa_cert_subject_readable(uid->uid);
+
+	    /* check the email field which may or may not be present */
+	    if (uid->email && !g_ascii_strcasecmp(uid->email, user_name))
+		uid_found = TRUE;
+	    else {
+		/* no email or no match, check the uid */
+		gchar *upcase_uid = g_ascii_strup(uid_info, -1);
+
+		if (strstr(upcase_uid, upcase_name))
+		    uid_found = TRUE;
+		else
+		    uid = uid->next;
+		g_free(upcase_uid);
+	    }
+	}
+
+	/* append the element */
+	if (subkey && uid) {
+	    gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
+	    gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
+			       GPG_KEY_USER_ID_COLUMN, uid_info,
+			       GPG_KEY_ID_COLUMN, subkey->keyid,
+			       GPG_KEY_LENGTH_COLUMN, subkey->length,
+			       GPG_KEY_VALIDITY_COLUMN,
+			       libbalsa_gpgme_validity_to_gchar_short(uid->
+								      validity),
+			       GPG_KEY_PTR_COLUMN, key, -1);
+	}
+	g_free(uid_info);
+	keys = g_list_next(keys);
+    }
+    g_free(upcase_name);
+
+    g_object_unref(G_OBJECT(model));
+    /* show the validity only if we are asking for a gpg public key */
+    last_col = (protocol == GPGME_PROTOCOL_CMS || secret) ?
+	GPG_KEY_LENGTH_COLUMN : GPG_KEY_VALIDITY_COLUMN;
+    for (i = 0; i <= last_col; i++) {
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	renderer = gtk_cell_renderer_text_new();
+	column =
+	    gtk_tree_view_column_new_with_attributes(_(col_titles[i]),
+						     renderer, "text", i,
+						     NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
+	gtk_tree_view_column_set_resizable(column, TRUE);
+    }
+
+    gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view);
+    gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
+    gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
+
+    if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK)
+	use_key = NULL;
+    gtk_widget_destroy(dialog);
+
+    return use_key;
+}
+
+
+gboolean
+lb_gpgme_accept_low_trust_key(const gchar * user_name,
+			      const gpgme_user_id_t user_id,
+			      GtkWindow * parent)
+{
+    GtkWidget *dialog;
+    gint result;
+    gchar *message1;
+    gchar *message2;
+
+    /* paranoia checks */
+    g_return_val_if_fail(user_id != NULL, FALSE);
+
+    /* build the message */
+    message1 =
+	g_strdup_printf(_("Insufficient trust for recipient %s"),
+			user_name);
+    message2 =
+	g_strdup_printf(_
+			("The validity of the key with user ID \"%s\" is \"%s\"."),
+			user_id->uid,
+			libbalsa_gpgme_validity_to_gchar_short(user_id->
+							       validity));
+    dialog =
+	gtk_message_dialog_new_with_markup(parent,
+					   GTK_DIALOG_DESTROY_WITH_PARENT,
+					   GTK_MESSAGE_WARNING,
+					   GTK_BUTTONS_YES_NO,
+					   "<b>%s</b>\n\n%s\n%s", message1,
+					   message2,
+					   _("Use this key anyway?"));
+#if HAVE_MACOSX_DESKTOP
+    libbalsa_macosx_menu_for_parent(dialog, parent);
+#endif
+
+    /* ask the user */
+    result = gtk_dialog_run(GTK_DIALOG(dialog));
+    gtk_widget_destroy(dialog);
+
+    return result == GTK_RESPONSE_YES;
+
+}
+
+
+#include "padlock-keyhole.xpm"
+
+
+static gchar *
+get_passphrase_real(const gchar * uid_hint, const gchar * passphrase_info,
+		    int prev_was_bad, GtkWindow * parent)
+{
+    static GdkPixbuf *padlock_keyhole = NULL;
+    GtkWidget *dialog, *entry, *vbox, *hbox;
+    gchar *prompt, *passwd;
+
+    /* FIXME: create dialog according to the Gnome HIG */
+    dialog = gtk_dialog_new_with_buttons(_("Enter Passphrase"), parent,
+					 GTK_DIALOG_DESTROY_WITH_PARENT,
+					 GTK_STOCK_OK, GTK_RESPONSE_OK,
+					 GTK_STOCK_CANCEL,
+					 GTK_RESPONSE_CANCEL, NULL);
+#if HAVE_MACOSX_DESKTOP
+    libbalsa_macosx_menu_for_parent(dialog, parent);
+#endif
+    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
+    gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
+    gtk_container_add(GTK_CONTAINER
+		      (gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
+		      hbox);
+
+    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
+    gtk_container_add(GTK_CONTAINER(hbox), vbox);
+    if (!padlock_keyhole)
+	padlock_keyhole =
+	    gdk_pixbuf_new_from_xpm_data(padlock_keyhole_xpm);
+    gtk_box_pack_start(GTK_BOX(vbox),
+		       gtk_image_new_from_pixbuf(padlock_keyhole), FALSE,
+		       FALSE, 0);
+    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
+    gtk_container_add(GTK_CONTAINER(hbox), vbox);
+    if (prev_was_bad)
+	prompt =
+	    g_strdup_printf(_
+			    ("%s\nThe passphrase for this key was bad, please try again!\n\nKey: %s"),
+			    passphrase_info, uid_hint);
+    else
+	prompt =
+	    g_strdup_printf(_
+			    ("%s\nPlease enter the passphrase for the secret key!\n\nKey: %s"),
+			    passphrase_info, uid_hint);
+    gtk_container_add(GTK_CONTAINER(vbox), gtk_label_new(prompt));
+    g_free(prompt);
+    entry = gtk_entry_new();
+    gtk_container_add(GTK_CONTAINER(vbox), entry);
+
+    gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
+    gtk_entry_set_width_chars(GTK_ENTRY(entry), 40);
+    gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+
+    gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+    gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+    gtk_widget_grab_focus(entry);
+    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
+	passwd = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+    else
+	passwd = NULL;
+
+    gtk_widget_destroy(dialog);
+
+    return passwd;
+}
+
+
+#ifdef BALSA_USE_THREADS
+/* get_passphrase_idle:
+   called in MT mode by the main thread.
+ */
+static gboolean
+get_passphrase_idle(gpointer data)
+{
+    ask_passphrase_data_t *apd = (ask_passphrase_data_t *) data;
+
+    gdk_threads_enter();
+    apd->res =
+	get_passphrase_real(apd->uid_hint, apd->passphrase_info,
+			    apd->was_bad, apd->parent);
+    gdk_threads_leave();
+    pthread_cond_signal(&apd->cond);
+    return FALSE;
+}
+#endif
+
+
+/* callback function if a new row is selected in the list */
+static void
+key_selection_changed_cb(GtkTreeSelection * selection, gpgme_key_t * key)
+{
+    GtkTreeIter iter;
+    GtkTreeModel *model;
+
+    if (gtk_tree_selection_get_selected(selection, &model, &iter))
+	gtk_tree_model_get(model, &iter, GPG_KEY_PTR_COLUMN, key, -1);
+}
diff --git a/libbalsa/libbalsa-gpgme-cb.h b/libbalsa/libbalsa-gpgme-cb.h
new file mode 100644
index 0000000..c0364bf
--- /dev/null
+++ b/libbalsa/libbalsa-gpgme-cb.h
@@ -0,0 +1,59 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * gpgme standard callback functions for balsa
+ * Copyright (C) 2011 Albrecht Dreà <albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef LIBBALSA_GPGME_CB_H_
+#define LIBBALSA_GPGME_CB_H_
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gpgme.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#ifdef MAKE_EMACS_HAPPY
+}
+#endif
+#endif				/* __cplusplus */
+
+
+gpgme_error_t lb_gpgme_passphrase(void *hook, const gchar * uid_hint,
+				  const gchar * passphrase_info,
+				  int prev_was_bad, int fd);
+gpgme_key_t lb_gpgme_select_key(const gchar * user_name, gboolean secret,
+				GList * keys, gpgme_protocol_t protocol,
+				GtkWindow * parent);
+gboolean lb_gpgme_accept_low_trust_key(const gchar * user_name,
+				       const gpgme_user_id_t user_id,
+				       GtkWindow * parent);
+
+
+#ifdef __cplusplus
+}
+#endif				/* __cplusplus */
+
+
+#endif				/* LIBBALSA_GPGME_CB_H_ */
diff --git a/libbalsa/libbalsa-gpgme.c b/libbalsa/libbalsa-gpgme.c
new file mode 100644
index 0000000..6932acb
--- /dev/null
+++ b/libbalsa/libbalsa-gpgme.c
@@ -0,0 +1,968 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * gpgme low-level stuff for gmime/balsa
+ * Copyright (C) 2011 Albrecht Dreà <albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#ifdef BALSA_USE_THREADS
+#include <pthread.h>
+#include "misc.h"
+#endif
+
+#if HAVE_MACOSX_DESKTOP
+#include "macosx-helpers.h"
+#endif
+
+#include <string.h>
+#include <gpgme.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gmime/gmime.h>
+#include "gmime-gpgme-signature.h"
+#include "libbalsa-gpgme.h"
+
+
+static void g_set_error_from_gpgme(GError ** error,
+				   gpgme_error_t gpgme_err,
+				   const gchar * message);
+static gpgme_error_t gpgme_new_with_protocol(gpgme_ctx_t * ctx,
+					     gpgme_protocol_t protocol,
+					     GtkWindow * parent,
+					     GError ** error);
+static gboolean gpgme_add_signer(gpgme_ctx_t ctx, const gchar * signer,
+				 GtkWindow * parent, GError ** error);
+static gpgme_key_t *gpgme_build_recipients(gpgme_ctx_t ctx,
+					   GPtrArray * rcpt_list,
+					   gboolean accept_low_trust,
+					   GtkWindow * parent,
+					   GError ** error);
+static void release_keylist(gpgme_key_t * keylist);
+
+/* callbacks for gpgme file handling */
+static ssize_t g_mime_gpgme_stream_rd(GMimeStream * stream, void *buffer,
+				      size_t size);
+static ssize_t g_mime_gpgme_stream_wr(GMimeStream * stream, void *buffer,
+				      size_t size);
+static void cb_data_release(void *handle);
+
+
+#if defined(ENABLE_NLS)
+static const gchar *get_utf8_locale(int category);
+#endif
+
+
+static gboolean has_proto_openpgp = FALSE;
+static gboolean has_proto_cms = FALSE;
+
+static gpgme_passphrase_cb_t gpgme_passphrase_cb = NULL;
+static lbgpgme_select_key_cb select_key_cb = NULL;
+static lbgpgme_accept_low_trust_cb accept_low_trust_cb = NULL;
+
+
+/** \brief Initialise GpgME
+ *
+ * \param get_passphrase Callback function to read a passphrase from the
+ *        user.  Note that this function is used \em only for OpenPGP and
+ *        \em only if no GPG Agent is running and can therefore usually be
+ *        NULL.  The first (HOOK) argument the passed function accepts
+ *        shall be the parent GtkWindow.
+ * \param select_key Callback function to let the user select a key from a
+ *        list if more than one is available.
+ * \param accept_low_trust Callback function to ask the user whether a low
+ *	  trust key shall be accepted.
+ *
+ * Initialise the GpgME backend and remember the callback functions.
+ *
+ * \note This function \em must be called before using any other function
+ *       from this module.
+ */
+void
+libbalsa_gpgme_init(gpgme_passphrase_cb_t get_passphrase,
+		    lbgpgme_select_key_cb select_key,
+		    lbgpgme_accept_low_trust_cb accept_low_trust)
+{
+    gpgme_engine_info_t e;
+    const gchar *agent_info;
+
+    /* initialise the gpgme library */
+    g_message("init gpgme version %s", gpgme_check_version(NULL));
+
+#ifdef HAVE_GPG
+    /* configure the GnuPG engine if a specific gpg path has been
+     * detected */
+    gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, GPG_PATH, NULL);
+#endif
+
+#ifdef ENABLE_NLS
+    gpgme_set_locale(NULL, LC_CTYPE, get_utf8_locale(LC_CTYPE));
+    gpgme_set_locale(NULL, LC_MESSAGES, get_utf8_locale(LC_MESSAGES));
+#endif				/* ENABLE_NLS */
+
+    /* dump the available engines */
+    if (gpgme_get_engine_info(&e) == GPG_ERR_NO_ERROR) {
+	while (e) {
+	    g_message("protocol %s: engine %s (home %s, version %s)",
+		      gpgme_get_protocol_name(e->protocol),
+		      e->file_name, e->home_dir, e->version);
+	    e = e->next;
+	}
+    }
+
+    /* check for gpg-agent */
+    agent_info = g_getenv("GPG_AGENT_INFO");
+    if (agent_info) {
+	g_message("gpg-agent found: %s", agent_info);
+	gpgme_passphrase_cb = NULL;
+    } else {
+	gpgme_passphrase_cb = get_passphrase;
+    }
+
+    /* verify that the engines we need are there */
+    if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) ==
+	GPG_ERR_NO_ERROR) {
+	g_message("OpenPGP protocol supported");
+	has_proto_openpgp = TRUE;
+    } else {
+	g_warning
+	    ("OpenPGP protocol not supported, basic crypto will not work!");
+	has_proto_openpgp = FALSE;
+    }
+
+#ifdef HAVE_SMIME
+    if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) ==
+	GPG_ERR_NO_ERROR) {
+	g_message("CMS (aka S/MIME) protocol supported");
+	has_proto_cms = TRUE;
+    } else {
+	g_warning("CMS protocol not supported, S/MIME will not work!");
+	has_proto_cms = FALSE;
+    }
+#else
+    g_message("built without CMS (aka S/MIME) protocol support");
+    has_proto_cms = FALSE;
+#endif
+
+    /* remember callbacks */
+    select_key = select_key_cb;
+    accept_low_trust = accept_low_trust_cb;
+}
+
+
+/** \brief Check if a crypto engine is available
+ *
+ * \param protocol Protocol for which the engine is checked.
+ * \return TRUE is the engine for the passed protocol is available.
+ *
+ * Check the availability of the crypto engine for a specific protocol.
+ */
+gboolean
+libbalsa_gpgme_check_crypto_engine(gpgme_protocol_t protocol)
+{
+    switch (protocol) {
+    case GPGME_PROTOCOL_OpenPGP:
+	return has_proto_openpgp;
+    case GPGME_PROTOCOL_CMS:
+	return has_proto_cms;
+    default:
+	return FALSE;
+    }
+}
+
+
+/** \brief Verify a signature
+ *
+ * \param content GMime stream of the signed matter.
+ * \param sig_plain GMime signature stream for a detached signature, or the
+ *        output stream for the checked matter in single-part mode.
+ * \param protocol GpgME crypto protocol of the signature.
+ * \param singlepart_mode TRUE indicates single-part mode (i.e. sig_plain
+ *        an output stream).
+ * \param error Filled with error information on error.
+ * \return A new signature status object on success, or NULL on error.
+ *
+ * Verify a signature by calling GpgME on the passed streams, and create a
+ * new signature object on success.
+ */
+GMimeGpgmeSigstat *
+libbalsa_gpgme_verify(GMimeStream * content, GMimeStream * sig_plain,
+		      gpgme_protocol_t protocol, gboolean singlepart_mode,
+		      GError ** error)
+{
+    gpgme_error_t err;
+    gpgme_ctx_t ctx;
+    struct gpgme_data_cbs cbs = {
+	(gpgme_data_read_cb_t) g_mime_gpgme_stream_rd,	/* read method */
+	(gpgme_data_write_cb_t) g_mime_gpgme_stream_wr,	/* write method */
+	NULL,			/* seek method */
+	cb_data_release		/* release method */
+    };
+    gpgme_data_t cont_data;
+    gpgme_data_t sig_plain_data;
+    GMimeGpgmeSigstat *result;
+
+    /* paranoia checks */
+    g_return_val_if_fail(GMIME_IS_STREAM(content), NULL);
+    g_return_val_if_fail(GMIME_IS_STREAM(sig_plain), NULL);
+    g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP ||
+			 protocol == GPGME_PROTOCOL_CMS, NULL);
+
+    /* create the GpgME context */
+    if ((err =
+	 gpgme_new_with_protocol(&ctx, protocol, NULL,
+				 error)) != GPG_ERR_NO_ERROR)
+	return NULL;
+
+    /* create the message stream */
+    if ((err =
+	 gpgme_data_new_from_cbs(&cont_data, &cbs,
+				 content)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not get data from stream"));
+	gpgme_release(ctx);
+	return NULL;
+    }
+
+    /* create data object for the detached signature stream or the
+     * "decrypted" plaintext */
+    if ((err =
+	 gpgme_data_new_from_cbs(&sig_plain_data, &cbs,
+				 sig_plain)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not get data from stream"));
+	gpgme_data_release(cont_data);
+	gpgme_release(ctx);
+	return NULL;
+    }
+
+    /* verify the signature */
+    if (singlepart_mode)
+	err = gpgme_op_verify(ctx, cont_data, NULL, sig_plain_data);
+    else
+	err = gpgme_op_verify(ctx, sig_plain_data, cont_data, NULL);
+    if (err != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("signature verification failed"));
+	result = g_mime_gpgme_sigstat_new();
+	result->status = err;
+	result->protocol = gpgme_get_protocol(ctx);
+    } else
+	result = g_mime_gpgme_sigstat_new_from_gpgme_ctx(ctx);
+
+    /* release gmgme data buffers, destroy the context and return the
+     * signature object */
+    gpgme_data_release(cont_data);
+    gpgme_data_release(sig_plain_data);
+    gpgme_release(ctx);
+    return result;
+}
+
+
+/** \brief Sign data
+ *
+ * \param userid User ID of the signer.
+ * \param istream GMime input stream.
+ * \param ostream GMime output stream.
+ * \param protocol GpgME crypto protocol of the signature.
+ * \param singlepart_mode TRUE indicates single-part mode (integrated
+ *        signature), FALSE a detached signature.
+ * \param parent Parent window to be passed to the passphrase callback
+ *        function.
+ * \param error Filled with error information on error.
+ * \return The hash algorithm used for creating the signature, or
+ *         GPGME_MD_NONE on error.
+ *
+ * Sign the passed matter and write the detached signature or the signed
+ * input and the signature, respectively, to the output stream.  The global
+ * callback to read the passphrase for the user's private key will be
+ * called by GpgME if no GPG Agent is running.
+ */
+gpgme_hash_algo_t
+libbalsa_gpgme_sign(const gchar * userid, GMimeStream * istream,
+		    GMimeStream * ostream, gpgme_protocol_t protocol,
+		    gboolean singlepart_mode, GtkWindow * parent,
+		    GError ** error)
+{
+    gpgme_error_t err;
+    gpgme_ctx_t ctx;
+    gpgme_sig_mode_t sig_mode;
+    gpgme_data_t in;
+    gpgme_data_t out;
+    gpgme_hash_algo_t hash_algo;
+    struct gpgme_data_cbs cbs = {
+	(gpgme_data_read_cb_t) g_mime_gpgme_stream_rd,	/* read method */
+	(gpgme_data_write_cb_t) g_mime_gpgme_stream_wr,	/* write method */
+	NULL,			/* seek method */
+	cb_data_release		/* release method */
+    };
+
+    /* paranoia checks */
+    g_return_val_if_fail(GMIME_IS_STREAM(istream), GPGME_MD_NONE);
+    g_return_val_if_fail(GMIME_IS_STREAM(ostream), GPGME_MD_NONE);
+    g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP ||
+			 protocol == GPGME_PROTOCOL_CMS, GPGME_MD_NONE);
+
+    /* create the GpgME context */
+    if ((err =
+	 gpgme_new_with_protocol(&ctx, protocol, parent,
+				 error)) != GPG_ERR_NO_ERROR)
+	return GPGME_MD_NONE;
+
+    /* set the signature mode */
+    if (singlepart_mode) {
+	if (protocol == GPGME_PROTOCOL_OpenPGP)
+	    sig_mode = GPGME_SIG_MODE_CLEAR;
+	else
+	    sig_mode = GPGME_SIG_MODE_NORMAL;
+    } else
+	sig_mode = GPGME_SIG_MODE_DETACH;
+
+    /* find the secret key for the "sign_for" address */
+    if (!gpgme_add_signer(ctx, userid, parent, error)) {
+	gpgme_release(ctx);
+	return GPGME_MD_NONE;
+    }
+
+    /* OpenPGP signatures are ASCII armored */
+    gpgme_set_armor(ctx, protocol == GPGME_PROTOCOL_OpenPGP);
+
+    /* create gpgme data objects */
+    if ((err =
+	 gpgme_data_new_from_cbs(&in, &cbs,
+				 istream)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not get data from stream"));
+	gpgme_release(ctx);
+	return GPGME_MD_NONE;
+    }
+    if ((err =
+	 gpgme_data_new_from_cbs(&out, &cbs,
+				 ostream)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not create new data object"));
+	gpgme_data_release(in);
+	gpgme_release(ctx);
+	return GPGME_MD_NONE;
+    }
+
+    /* sign and get the used hash algorithm */
+    err = gpgme_op_sign(ctx, in, out, sig_mode);
+    if (err != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err, _("signing failed"));
+	hash_algo = GPGME_MD_NONE;
+    } else
+	hash_algo = gpgme_op_sign_result(ctx)->signatures->hash_algo;
+
+    /* clean up */
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    return hash_algo;
+}
+
+
+/** \brief Encrypt data
+ *
+ * \param recipients Array of User ID for which the matter shall be
+ *        encrypted using their public keys.
+ * \param sign_for User ID of the signer or NULL if the matter shall not be
+ *        signed.  Note that combined signing and encryption is allowed \em
+ *        only in OpenPGP single-part (i.e. RFC 2440) mode.
+ * \param istream GMime input stream.
+ * \param ostream GMime output stream.
+ * \param protocol GpgME crypto protocol to use for encryption.
+ * \param singlepart_mode TRUE indicates single-part mode (integrated
+ *        signature), FALSE a detached signature.
+ * \param trust_all_keys TRUE if all low-truct keys shall be accepted for
+ *        encryption.  Otherwise, the function will use the global callback
+ *        to ask the user whether a low-trust key shall be accepted.
+ * \param parent Parent window to be passed to the callback functions.
+ * \param error Filled with error information on error.
+ * \return 0 on success, or -1 on error.
+ *
+ * Encrypt the passed matter and write the result to the output stream.
+ * Combined signing and encryption is allowed for single-part OpenPGP mode
+ * only.
+ */
+int
+libbalsa_gpgme_encrypt(GPtrArray * recipients, const char *sign_for,
+		       GMimeStream * istream, GMimeStream * ostream,
+		       gpgme_protocol_t protocol, gboolean singlepart_mode,
+		       gboolean trust_all_keys, GtkWindow * parent,
+		       GError ** error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t err;
+    gpgme_key_t *rcpt_keys;
+    gpgme_data_t plain;
+    gpgme_data_t crypt;
+    struct gpgme_data_cbs cbs = {
+	(gpgme_data_read_cb_t) g_mime_gpgme_stream_rd,	/* read method */
+	(gpgme_data_write_cb_t) g_mime_gpgme_stream_wr,	/* write method */
+	NULL,			/* seek method */
+	cb_data_release		/* release method */
+    };
+
+    /* paranoia checks */
+    g_return_val_if_fail(recipients != NULL, -1);
+    g_return_val_if_fail(GMIME_IS_STREAM(istream), -1);
+    g_return_val_if_fail(GMIME_IS_STREAM(ostream), GPGME_MD_NONE);
+    g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP ||
+			 protocol == GPGME_PROTOCOL_CMS, -1);
+
+    /* create the GpgME context */
+    if ((err =
+	 gpgme_new_with_protocol(&ctx, protocol, parent,
+				 error)) != GPG_ERR_NO_ERROR)
+	return -1;
+
+    /* sign & encrypt is valid only for single-part OpenPGP */
+    if (sign_for != NULL
+	&& (!singlepart_mode || protocol != GPGME_PROTOCOL_OpenPGP)) {
+	if (error)
+	    g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_INV_ENGINE,
+			_
+			("combined signing and encryption is defined only for RFC 2440"));
+	gpgme_release(ctx);
+	return -1;
+    }
+
+    /* if requested, find the secret key for "userid" */
+    if (sign_for && !gpgme_add_signer(ctx, sign_for, parent, error)) {
+	gpgme_release(ctx);
+	return -1;
+    }
+
+    /* build the list of recipients */
+    if (!
+	(rcpt_keys =
+	 gpgme_build_recipients(ctx, recipients, trust_all_keys, parent,
+				error))) {
+	gpgme_release(ctx);
+	return -1;
+    }
+
+    /* create the data objects */
+    if (protocol == GPGME_PROTOCOL_OpenPGP) {
+	gpgme_set_armor(ctx, 1);
+	gpgme_set_textmode(ctx, singlepart_mode);
+    } else {
+	gpgme_set_armor(ctx, 0);
+	gpgme_set_textmode(ctx, 0);
+    }
+    if ((err =
+	 gpgme_data_new_from_cbs(&plain, &cbs,
+				 istream)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not get data from stream"));
+	release_keylist(rcpt_keys);
+	gpgme_release(ctx);
+	return -1;
+    }
+    if ((err =
+	 gpgme_data_new_from_cbs(&crypt, &cbs,
+				 ostream)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not create new data object"));
+	release_keylist(rcpt_keys);
+	gpgme_data_release(plain);
+	gpgme_release(ctx);
+	return -1;
+    }
+
+    /* do the encrypt or sign and encrypt operation
+     * Note: we set "always trust" here, as if we detected an untrusted key
+     * earlier, the user already accepted it */
+    if (sign_for)
+	err =
+	    gpgme_op_encrypt_sign(ctx, rcpt_keys,
+				  GPGME_ENCRYPT_ALWAYS_TRUST, plain,
+				  crypt);
+    else
+	err =
+	    gpgme_op_encrypt(ctx, rcpt_keys, GPGME_ENCRYPT_ALWAYS_TRUST,
+			     plain, crypt);
+
+    release_keylist(rcpt_keys);
+    gpgme_data_release(plain);
+    gpgme_data_release(crypt);
+    gpgme_release(ctx);
+    if (err != GPG_ERR_NO_ERROR) {
+	if (sign_for)
+	    g_set_error_from_gpgme(error, err,
+				   _("signing and encryption failed"));
+	else
+	    g_set_error_from_gpgme(error, err, _("encryption failed"));
+	return -1;
+    } else
+	return 0;
+}
+
+
+/** \brief Decrypt data
+ *
+ * \param istream GMime input (encrypted) stream.
+ * \param ostream GMime output (decrypted) stream.
+ * \param protocol GpgME crypto protocol to use.
+ * \param parent Parent window to be passed to the passphrase callback
+ *        function.
+ * \param error Filled with error information on error.
+ * \return A new signature status object on success, or NULL on error.
+ *
+ * Decrypt and -if applicable- verify the signature of the passed data
+ * stream.  If the input is not signed the returned signature status will
+ * be GPG_ERR_NOT_SIGNED.
+ */
+GMimeGpgmeSigstat *
+libbalsa_gpgme_decrypt(GMimeStream * crypted, GMimeStream * plain,
+		       gpgme_protocol_t protocol, GtkWindow * parent,
+		       GError ** error)
+{
+    gpgme_ctx_t ctx;
+    gpgme_error_t err;
+    gpgme_data_t plain_data;
+    gpgme_data_t crypt_data;
+    GMimeGpgmeSigstat *result;
+    struct gpgme_data_cbs cbs = {
+	(gpgme_data_read_cb_t) g_mime_gpgme_stream_rd,	/* read method */
+	(gpgme_data_write_cb_t) g_mime_gpgme_stream_wr,	/* write method */
+	NULL,			/* seek method */
+	cb_data_release		/* release method */
+    };
+
+    /* paranoia checks */
+    g_return_val_if_fail(GMIME_IS_STREAM(crypted), NULL);
+    g_return_val_if_fail(GMIME_IS_STREAM(plain), NULL);
+    g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP ||
+			 protocol == GPGME_PROTOCOL_CMS, NULL);
+
+    /* create the GpgME context */
+    if ((err =
+	 gpgme_new_with_protocol(&ctx, protocol, parent,
+				 error)) != GPG_ERR_NO_ERROR)
+	return NULL;
+
+    /* create the data streams */
+    if ((err =
+	 gpgme_data_new_from_cbs(&crypt_data, &cbs,
+				 crypted)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not get data from stream"));
+	gpgme_release(ctx);
+	return NULL;
+    }
+    if ((err =
+	 gpgme_data_new_from_cbs(&plain_data, &cbs,
+				 plain)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err,
+			       _("could not create new data object"));
+	gpgme_data_release(crypt_data);
+	gpgme_release(ctx);
+	return NULL;
+    }
+
+    /* try to decrypt */
+    if ((err =
+	 gpgme_op_decrypt_verify(ctx, crypt_data,
+				 plain_data)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err, _("decryption failed"));
+	result = NULL;
+    } else {
+	/* decryption successful, check for signature */
+	result = g_mime_gpgme_sigstat_new_from_gpgme_ctx(ctx);
+    }
+
+    /* clean up */
+    gpgme_data_release(plain_data);
+    gpgme_data_release(crypt_data);
+    gpgme_release(ctx);
+
+    return result;
+}
+
+/* ---- local stuff ---------------------------------------------------- */
+
+#define UTF8_VALID_STR(s)						\
+    do {								\
+	if ((s) && !g_utf8_validate(s, -1, NULL)) {			\
+	    gsize bwr;							\
+	    gchar * newstr = g_locale_to_utf8(s, -1, NULL, &bwr, NULL);	\
+									\
+	    g_free(s);							\
+	    s = newstr;							\
+	}								\
+    } while (0)
+
+
+/*
+ * set a GError form GpgME information
+ */
+static void
+g_set_error_from_gpgme(GError ** error, gpgme_error_t gpgme_err,
+		       const gchar * message)
+{
+    gchar *errstr;
+    gchar *srcstr;
+
+    if (!error)
+	return;
+
+    srcstr = g_strdup(gpgme_strsource(gpgme_err));
+    UTF8_VALID_STR(srcstr);
+    errstr = g_strdup(gpgme_strerror(gpgme_err));
+    UTF8_VALID_STR(errstr);
+    g_set_error(error, GPGME_ERROR_QUARK, gpgme_err, "%s: %s: %s", srcstr,
+		message, errstr);
+    g_free(srcstr);
+    g_free(errstr);
+}
+
+
+/*
+ * callback to get data from a stream
+ */
+static ssize_t
+g_mime_gpgme_stream_rd(GMimeStream * stream, void *buffer, size_t size)
+{
+    ssize_t result;
+
+    result = g_mime_stream_read(stream, buffer, size);
+    if (result == -1 && g_mime_stream_eos(stream))
+	result = 0;
+
+    return result;
+}
+
+
+/*
+ * callback to write data to a stream
+ */
+static ssize_t
+g_mime_gpgme_stream_wr(GMimeStream * stream, void *buffer, size_t size)
+{
+    return g_mime_stream_write(stream, buffer, size);
+}
+
+
+/*
+ * dummy function for callback based gpgme data objects
+ */
+static void
+cb_data_release(void *handle)
+{
+    /* must just be present... bug or feature?!? */
+}
+
+
+/*
+ * create a GpgME context for the passed protocol
+ */
+static gpgme_error_t
+gpgme_new_with_protocol(gpgme_ctx_t * ctx, gpgme_protocol_t protocol,
+			GtkWindow * parent, GError ** error)
+{
+    gpgme_error_t err;
+
+
+    /* create the GpgME context */
+    if ((err = gpgme_new(ctx)) != GPG_ERR_NO_ERROR) {
+	g_set_error_from_gpgme(error, err, _("could not create context"));
+    } else {
+	if ((err = gpgme_set_protocol(*ctx, protocol)) != GPG_ERR_NO_ERROR) {
+	    gchar *errmsg =
+		g_strdup_printf(_("could not set protocol '%s'"),
+				gpgme_get_protocol_name(protocol));
+
+	    g_set_error_from_gpgme(error, err, errmsg);
+	    g_free(errmsg);
+	    gpgme_release(*ctx);
+	} else {
+	    if (protocol == GPGME_PROTOCOL_OpenPGP)
+		gpgme_set_passphrase_cb(*ctx, gpgme_passphrase_cb, parent);
+	}
+    }
+
+    return err;
+}
+
+
+/*
+ * Get a key for name. If secret_only is set, choose only secret (private)
+ * keys (signing). Otherwise, choose only public keys (encryption).
+ * If multiple keys would match, call the key selection CB (if present). If
+ * no matching key could be found or if any error occurs, return NULL and
+ * set error.
+ */
+#define KEY_IS_OK(k)   (!((k)->expired || (k)->revoked || \
+                          (k)->disabled || (k)->invalid))
+static gpgme_key_t
+get_key_from_name(gpgme_ctx_t ctx, const gchar * name, gboolean secret,
+		  gboolean accept_all, GtkWindow * parent, GError ** error)
+{
+    GList *keys = NULL;
+    gpgme_key_t key;
+    gpgme_error_t err;
+    gboolean found_bad;
+    time_t now = time(NULL);
+
+    /* let gpgme list keys */
+    if ((err =
+	 gpgme_op_keylist_start(ctx, name, secret)) != GPG_ERR_NO_ERROR) {
+	gchar *msg =
+	    g_strdup_printf(_("could not list keys for \"%s\""), name);
+
+	g_set_error_from_gpgme(error, err, msg);
+	g_free(msg);
+	return NULL;
+    }
+
+    found_bad = FALSE;
+    while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) {
+	/* check if this key and the relevant subkey are usable */
+	if (KEY_IS_OK(key)) {
+	    gpgme_subkey_t 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))
+		keys = g_list_append(keys, key);
+	    else
+		found_bad = TRUE;
+	} else
+	    found_bad = TRUE;
+    }
+
+    if (gpg_err_code(err) != GPG_ERR_EOF) {
+	gchar *msg =
+	    g_strdup_printf(_("could not list keys for \"%s\""), name);
+
+	g_set_error_from_gpgme(error, err, msg);
+	g_free(msg);
+	gpgme_op_keylist_end(ctx);
+	g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL);
+	g_list_free(keys);
+	return NULL;
+    }
+    gpgme_op_keylist_end(ctx);
+
+    if (!keys) {
+	if (error) {
+	    if (strchr(name, '@')) {
+		if (found_bad)
+		    g_set_error(error, GPGME_ERROR_QUARK,
+				GPG_ERR_KEY_SELECTION,
+				_
+				("%s: a key for %s is present, but it is expired, disabled, revoked or invalid"),
+				"gmime-gpgme", name);
+		else
+		    g_set_error(error, GPGME_ERROR_QUARK,
+				GPG_ERR_KEY_SELECTION,
+				_("%s: could not find a key for %s"),
+				"gmime-gpgme", name);
+	    } else {
+		if (found_bad)
+		    g_set_error(error, GPGME_ERROR_QUARK,
+				GPG_ERR_KEY_SELECTION,
+				_
+				("%s: a key with id %s is present, but it is expired, disabled, revoked or invalid"),
+				"gmime-gpgme", name);
+		else
+		    g_set_error(error, GPGME_ERROR_QUARK,
+				GPG_ERR_KEY_SELECTION,
+				_("%s: could not find a key with id %s"),
+				"gmime-gpgme", name);
+	    }
+	}
+	return NULL;
+    }
+
+    /* let the user select a key from the list if there is more than one */
+    if (g_list_length(keys) > 1) {
+	if (select_key_cb)
+	    key =
+		select_key_cb(name, secret, keys, gpgme_get_protocol(ctx),
+			      parent);
+	else {
+	    if (error)
+		g_set_error(error, GPGME_ERROR_QUARK,
+			    GPG_ERR_KEY_SELECTION,
+			    _("%s: multiple keys for %s"), "gmime-gpgme",
+			    name);
+	    key = NULL;
+	}
+	if (key)
+	    gpgme_key_ref(key);
+	g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL);
+    } else
+	key = (gpgme_key_t) keys->data;
+    g_list_free(keys);
+
+    /* OpenPGP: ask the user if a low-validity key should be trusted for
+     * encryption */
+    // FIXME - shouldn't we do the same for S/MIME?
+    if (key && !secret && !accept_all
+	&& gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
+	gpgme_user_id_t uid = key->uids;
+	gchar *upcase_name = g_ascii_strup(name, -1);
+	gboolean found = FALSE;
+
+	while (!found && uid) {
+	    /* check the email field which may or may not be present */
+	    if (uid->email && !g_ascii_strcasecmp(uid->email, name))
+		found = TRUE;
+	    else {
+		/* no email or no match, check the uid */
+		gchar *upcase_uid = g_ascii_strup(uid->uid, -1);
+
+		if (strstr(upcase_uid, upcase_name))
+		    found = TRUE;
+		else
+		    uid = uid->next;
+		g_free(upcase_uid);
+	    }
+	}
+	g_free(upcase_name);
+
+	/* ask the user if a low-validity key shall be used */
+	if (uid && uid->validity < GPGME_VALIDITY_FULL) {
+	    if (!accept_low_trust_cb
+		|| !accept_low_trust_cb(name, uid, parent)) {
+		gpgme_key_unref(key);
+		key = NULL;
+		if (error)
+		    g_set_error(error, GPGME_ERROR_QUARK,
+				GPG_ERR_KEY_SELECTION,
+				_("%s: insufficient validity for uid %s"),
+				"gmime-gpgme", name);
+	    }
+	}
+    }
+
+    return key;
+}
+
+
+/*
+ * Add signer to ctx's list of signers and return TRUE on success or FALSE
+ * on error.
+ */
+static gboolean
+gpgme_add_signer(gpgme_ctx_t ctx, const gchar * signer, GtkWindow * parent,
+		 GError ** error)
+{
+    gpgme_key_t key = NULL;
+
+    /* note: private (secret) key has never low trust... */
+    if (!
+	(key = get_key_from_name(ctx, signer, TRUE, FALSE, parent, error)))
+	return FALSE;
+
+    /* set the key (the previous operation guaranteed that it exists, no
+     * need 2 check return values...) */
+    gpgme_signers_add(ctx, key);
+    gpgme_key_unref(key);
+
+    return TRUE;
+}
+
+
+/*
+ * Build a NULL-terminated array of keys for all recipients in rcpt_list
+ * and return it. The caller has to take care that it's released. If
+ * something goes wrong, NULL is returned.
+ */
+static gpgme_key_t *
+gpgme_build_recipients(gpgme_ctx_t ctx, GPtrArray * rcpt_list,
+		       gboolean accept_low_trust, GtkWindow * parent,
+		       GError ** error)
+{
+    gpgme_key_t *rcpt = g_new0(gpgme_key_t, rcpt_list->len + 1);
+    guint num_rcpts;
+
+    /* try to find the public key for every recipient */
+    for (num_rcpts = 0; num_rcpts < rcpt_list->len; num_rcpts++) {
+	gchar *name = (gchar *) g_ptr_array_index(rcpt_list, num_rcpts);
+	gpgme_key_t key;
+
+	if (!
+	    (key =
+	     get_key_from_name(ctx, name, FALSE, accept_low_trust, parent,
+			       error))) {
+	    release_keylist(rcpt);
+	    return NULL;
+	}
+
+	/* set the recipient */
+	rcpt[num_rcpts] = key;
+    }
+
+    return rcpt;
+}
+
+
+/*
+ * helper function: unref all keys in the NULL-terminated array keylist and
+ * finally release the array itself
+ */
+static void
+release_keylist(gpgme_key_t * keylist)
+{
+    gpgme_key_t *key = keylist;
+
+    while (*key) {
+	gpgme_key_unref(*key);
+	key++;
+    }
+    g_free(keylist);
+}
+
+
+#if defined(ENABLE_NLS)
+/*
+ * convert a locale name to utf-8
+ */
+static const gchar *
+get_utf8_locale(int category)
+{
+    gchar *locale;
+    static gchar localebuf[64];	/* should be large enough */
+    gchar *dot;
+
+    if (!(locale = setlocale(category, NULL)))
+	return NULL;
+    strncpy(localebuf, locale, 57);
+    localebuf[57] = '\0';
+    dot = strchr(localebuf, '.');
+    if (!dot)
+	dot = localebuf + strlen(localebuf);
+    strcpy(dot, ".UTF-8");
+    return localebuf;
+}
+#endif
diff --git a/libbalsa/libbalsa-gpgme.h b/libbalsa/libbalsa-gpgme.h
new file mode 100644
index 0000000..3a865f5
--- /dev/null
+++ b/libbalsa/libbalsa-gpgme.h
@@ -0,0 +1,115 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * gpgme low-level stuff for gmime/balsa
+ * Copyright (C) 2011 Albrecht Dreà <albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef LIBBALSA_GPGME_H_
+#define LIBBALSA_GPGME_H_
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gpgme.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gmime/gmime.h>
+#include "gmime-gpgme-signature.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#ifdef MAKE_EMACS_HAPPY
+}
+#endif
+#endif				/* __cplusplus */
+
+
+#define GPG_ERR_KEY_SELECTION          GPG_ERR_USER_14
+#define GPG_ERR_TRY_AGAIN              GPG_ERR_USER_15
+#define GPG_ERR_NOT_SIGNED             GPG_ERR_USER_16
+
+#define GPGME_ERROR_QUARK (g_quark_from_static_string("gmime-gpgme"))
+
+
+/** Callback to select a key from a list
+ * Parameters:
+ * - user name
+ * - TRUE is a secret key shall be selected
+ * - list of available keys (gpgme_key_t data elements)
+ * - protocol
+ * - parent window
+ */ typedef gpgme_key_t(*lbgpgme_select_key_cb) (const gchar *,
+						 gboolean,
+						 GList *,
+						 gpgme_protocol_t,
+						 GtkWindow *);
+
+/** Callback to ask the user whether a key with low trust shall be accepted
+ * Parameters:
+ * - user name
+ * - GpgME user ID
+ * - parent window
+ */
+typedef gboolean(*lbgpgme_accept_low_trust_cb) (const gchar *,
+						const gpgme_user_id_t,
+						GtkWindow *);
+
+
+
+void libbalsa_gpgme_init(gpgme_passphrase_cb_t get_passphrase,
+			 lbgpgme_select_key_cb select_key_cb,
+			 lbgpgme_accept_low_trust_cb accept_low_trust);
+gboolean libbalsa_gpgme_check_crypto_engine(gpgme_protocol_t protocol);
+
+GMimeGpgmeSigstat *libbalsa_gpgme_verify(GMimeStream * content,
+					 GMimeStream * sig_plain,
+					 gpgme_protocol_t protocol,
+					 gboolean singlepart_mode,
+					 GError ** error);
+
+gpgme_hash_algo_t libbalsa_gpgme_sign(const gchar * userid,
+				      GMimeStream * istream,
+				      GMimeStream * ostream,
+				      gpgme_protocol_t protocol,
+				      gboolean singlepart_mode,
+				      GtkWindow * parent, GError ** error);
+
+int libbalsa_gpgme_encrypt(GPtrArray * recipients,
+			   const char *sign_for,
+			   GMimeStream * istream,
+			   GMimeStream * ostream,
+			   gpgme_protocol_t protocol,
+			   gboolean singlepart_mode,
+			   gboolean trust_all_keys,
+			   GtkWindow * parent, GError ** error);
+
+GMimeGpgmeSigstat *libbalsa_gpgme_decrypt(GMimeStream * crypted,
+					  GMimeStream * plain,
+					  gpgme_protocol_t protocol,
+					  GtkWindow * parent,
+					  GError ** error);
+
+
+#ifdef __cplusplus
+}
+#endif				/* __cplusplus */
+
+#endif				/* LIBBALSA_GPGME_H_ */
diff --git a/libbalsa/rfc3156.c b/libbalsa/rfc3156.c
index e6072c4..c11f64e 100644
--- a/libbalsa/rfc3156.c
+++ b/libbalsa/rfc3156.c
@@ -35,7 +35,7 @@
 #include "libbalsa.h"
 #include "libbalsa_private.h"
 
-#include "gmime-gpgme-context.h"
+#include "gmime-multipart-crypt.h"
 #include "gmime-gpgme-signature.h"
 #include "gmime-part-rfc2440.h"
 
@@ -52,88 +52,16 @@
 #  include "macosx-helpers.h"
 #endif
 
-#include "padlock-keyhole.xpm"
 #include <glib/gi18n.h>
 
 
 /* local prototypes */
-static const gchar *libbalsa_gpgme_validity_to_gchar_short(gpgme_validity_t
-							   validity);
-static gpgme_error_t get_passphrase_cb(void *opaque, const char *uid_hint,
-				       const char *passph_info,
-				       int prev_wasbad, int fd);
-static gpgme_key_t select_key_from_list(const gchar * name,
-					gboolean is_secret,
-					GMimeGpgmeContext * ctx,
-					GList * keys);
-static gboolean accept_low_trust_key(const gchar * name,
-				     gpgme_user_id_t uid,
-				     GMimeGpgmeContext * ctx);
 static gboolean gpg_updates_trustdb(void);
-static gchar *fix_EMail_info(gchar * str);
 static gboolean have_pub_key_for(gpgme_ctx_t gpgme_ctx,
 				 InternetAddressList * recipients);
 
 
 /* ==== public functions =================================================== */
-gboolean
-libbalsa_check_crypto_engine(gpgme_protocol_t protocol)
-{
-    gpgme_error_t err;
-
-    err = gpgme_engine_check_version(protocol);
-    if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
-	gpgme_engine_info_t info;
-	GString *message = g_string_new("");
-	err = gpgme_get_engine_info(&info);
-	if (err == GPG_ERR_NO_ERROR) {
-	    while (info && info->protocol != protocol)
-		info = info->next;
-	    if (!info)
-		g_string_append_printf(message,
-				       _
-				       ("Gpgme has been compiled without support for protocol %s."),
-				       gpgme_get_protocol_name(protocol));
-	    else if (info->file_name && !info->version) {
-		g_string_append_printf(message,
-				       _
-				       ("Crypto engine %s is not installed properly."),
-				       info->file_name);
-                if (protocol == GPGME_PROTOCOL_OpenPGP)
-                    g_string_append_printf(message,
-                                           _(" Hint: check the `gnupg2' (preferred) or `gnupg' package."));
-                else if (protocol == GPGME_PROTOCOL_CMS)
-                    g_string_append_printf(message,
-                                           _(" Hint: check the `gpgsm' package."));
-	    } else if (info->file_name && info->version && info->req_version)
-		g_string_append_printf(message,
-				       _
-				       ("Crypto engine %s version %s is installed, but at least version %s is required."),
-				       info->file_name, info->version,
-				       info->req_version);
-
-	    else
-		g_string_append_printf(message,
-				       _
-				       ("Unknown problem with engine for protocol %s."),
-				       gpgme_get_protocol_name(protocol));
-	} else
-	    g_string_append_printf(message,
-				   _
-				   ("%s: could not retrieve crypto engine information: %s."),
-				   gpgme_strsource(err),
-				   gpgme_strerror(err));
-	g_string_append_printf(message,
-			       _("\nDisable support for protocol %s."),
-			       gpgme_get_protocol_name(protocol));
-	libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s", message->str);
-	g_string_free(message, TRUE);
-	return FALSE;
-    } else
-	return TRUE;
-}
-
-
 static gboolean
 body_is_type(LibBalsaMessageBody * body, const gchar * type,
 	     const gchar * sub_type)
@@ -266,42 +194,6 @@ libbalsa_message_body_protection(LibBalsaMessageBody * body)
     return result;
 }
 
-#if defined(HAVE_GMIME_2_6)
-static gboolean
-#ifndef HAVE_GMIME_2_5_7
-password_request_func(GMimeCipherContext * ctx, const char *user_id,
-                      const char *prompt_ctx, gboolean reprompt,
-                      GMimeStream * response, GError ** err)
-#else /* HAVE_GMIME_2_5_7 */
-password_request_func(GMimeCryptoContext * ctx, const char *user_id,
-                      const char *prompt_ctx, gboolean reprompt,
-                      GMimeStream * response, GError ** err)
-#endif /* HAVE_GMIME_2_5_7 */
-{
-    gint fd;
-    gchar *name_used;
-    gboolean rc;
-
-    fd = g_file_open_tmp(NULL, &name_used, NULL);
-    if (fd < 0)
-        return FALSE;
-
-    rc = get_passphrase_cb(ctx, user_id, prompt_ctx, reprompt, fd)
-        == GPG_ERR_NO_ERROR;
-    if (rc) {
-        GMimeStream *stream = g_mime_stream_fs_new(fd);
-        g_mime_stream_reset(stream);
-        g_mime_stream_write_to_stream(response, stream);
-
-        g_object_unref(stream);
-    }
-
-    unlink(name_used);
-    g_free(name_used);
-
-    return rc;
-}
-#endif                          /* HAVE_GMIME_2_6 */
 
 /* === RFC 2633/ RFC 3156 crypto routines === */
 /*
@@ -317,10 +209,6 @@ libbalsa_sign_mime_object(GMimeObject ** content, const gchar * rfc822_for,
 			  gpgme_protocol_t protocol, GtkWindow * parent,
 			  GError ** error)
 {
-#if !defined(HAVE_GMIME_2_6)
-    GMimeSession *session;
-#endif                          /* HAVE_GMIME_2_6 */
-    GMimeGpgmeContext *ctx;
     GMimeMultipartSigned *mps;
 
     /* paranoia checks */
@@ -334,70 +222,18 @@ libbalsa_sign_mime_object(GMimeObject ** content, const gchar * rfc822_for,
     if (protocol == GPGME_PROTOCOL_OpenPGP && gpg_updates_trustdb())
 	return FALSE;
 
-#if defined(HAVE_GMIME_2_6)
-    /* create a GMimeGpgmeContext */
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new
-            (password_request_func, protocol, error));
-    if (ctx == NULL)
-	return FALSE;
-#else                           /* HAVE_GMIME_2_6 */
-    /* create a session and a GMimeGpgmeContext */
-    session = g_object_new(g_mime_session_get_type(), NULL, NULL);
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new(session, protocol,
-						       error));
-    if (ctx == NULL) {
-	g_object_unref(session);
-	return FALSE;
-    }
-#endif                          /* HAVE_GMIME_2_6 */
-
-    /* set the callbacks for the passphrase entry and the key selection */
-    if (g_getenv("GPG_AGENT_INFO"))
-	ctx->passphrase_cb = NULL;  /* use gpg-agent */
-    else {
-	ctx->passphrase_cb = get_passphrase_cb;
-	g_object_set_data(G_OBJECT(ctx), "passphrase-info",
-			  _
-			  ("Enter passphrase to unlock the secret key for signing"));
-    }
-    ctx->key_select_cb = select_key_from_list;
-    g_object_set_data(G_OBJECT(ctx), "parent-window", parent);
-
     /* call gpgme to create the signature */
     if (!(mps = g_mime_multipart_signed_new())) {
-	g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
 	return FALSE;
     }
 
-#ifndef HAVE_GMIME_2_5_7
-    if (g_mime_multipart_signed_sign
-	(mps, *content, GMIME_CIPHER_CONTEXT(ctx), rfc822_for,
-	 GMIME_CIPHER_HASH_DEFAULT, error) != 0)
-#else /* HAVE_GMIME_2_5_7 */
-    if (g_mime_multipart_signed_sign
-	(mps, *content, GMIME_CRYPTO_CONTEXT(ctx), rfc822_for,
-	 GMIME_DIGEST_ALGO_DEFAULT, error) != 0)
-#endif /* HAVE_GMIME_2_5_7 */
-    {
+    if (g_mime_gpgme_mps_sign(mps, *content, rfc822_for, protocol, parent, error) != 0) {
 	g_object_unref(mps);
-	g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
 	return FALSE;
     }
 
-    g_mime_object_set_content_type_parameter(GMIME_OBJECT(mps),
-					     "micalg", ctx->micalg);
     g_object_unref(G_OBJECT(*content));
     *content = GMIME_OBJECT(mps);
-    g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-    g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
     return TRUE;
 }
 
@@ -412,10 +248,6 @@ libbalsa_encrypt_mime_object(GMimeObject ** content, GList * rfc822_for,
 			     gpgme_protocol_t protocol, gboolean always_trust,
 			     GtkWindow * parent, GError ** error)
 {
-#if !defined(HAVE_GMIME_2_6)
-    GMimeSession *session;
-#endif                          /* HAVE_GMIME_2_6 */
-    GMimeGpgmeContext *ctx;
     GMimeObject *encrypted_obj = NULL;
     GPtrArray *recipients;
     int result = -1;
@@ -431,32 +263,6 @@ libbalsa_encrypt_mime_object(GMimeObject ** content, GList * rfc822_for,
     if (protocol == GPGME_PROTOCOL_OpenPGP && gpg_updates_trustdb())
 	return FALSE;
 
-#if !defined(HAVE_GMIME_2_6)
-    /* create a session and a GMimeGpgmeContext */
-    session = g_object_new(g_mime_session_get_type(), NULL, NULL);
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new(session, protocol,
-						       error));
-    if (ctx == NULL) {
-	g_object_unref(session);
-	return FALSE;
-#else                           /* HAVE_GMIME_2_6 */
-    /* create a GMimeGpgmeContext */
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new
-            (password_request_func, protocol, error));
-    if (ctx == NULL)
-	return FALSE;
-#endif                          /* HAVE_GMIME_2_6 */
-#if !defined(HAVE_GMIME_2_6)
-    }
-#endif                          /* HAVE_GMIME_2_6 */
-
-    /* set the callback for the key selection (no secret needed here) */
-    ctx->key_select_cb = select_key_from_list;
-    if (!always_trust)
-	ctx->key_trust_cb = accept_low_trust_key;
-    ctx->always_trust_uid = always_trust;
-    g_object_set_data(G_OBJECT(ctx), "parent-window", parent);
-
     /* convert the key list to a GPtrArray */
     recipients = g_ptr_array_new();
     while (rfc822_for) {
@@ -470,60 +276,27 @@ libbalsa_encrypt_mime_object(GMimeObject ** content, GList * rfc822_for,
 	GMimeMultipartEncrypted *mpe = g_mime_multipart_encrypted_new();
 
 	encrypted_obj = GMIME_OBJECT(mpe);
-	result = 
-#ifndef HAVE_GMIME_2_5_7
-	    g_mime_multipart_encrypted_encrypt(mpe, *content,
-					       GMIME_CIPHER_CONTEXT(ctx),
-                                               FALSE, NULL,
-					       recipients, error);
-#else /* HAVE_GMIME_2_5_7 */
-	    g_mime_multipart_encrypted_encrypt(mpe, *content,
-					       GMIME_CRYPTO_CONTEXT(ctx),
-                                               FALSE, NULL,
-                                               GMIME_DIGEST_ALGO_DEFAULT,
-					       recipients, error);
-#endif /* HAVE_GMIME_2_5_7 */
+	result = g_mime_gpgme_mpe_encrypt(mpe, *content, recipients, always_trust, parent, error);
     }
 #ifdef HAVE_SMIME
     else {
 	GMimePart *pkcs7 =
 	    g_mime_part_new_with_type("application", "pkcs7-mime");
 
-	encrypted_obj = GMIME_OBJECT(pkcs7);
-	ctx->singlepart_mode = TRUE;
-	result = 
-#ifndef HAVE_GMIME_2_5_7
-	    g_mime_application_pkcs7_encrypt(pkcs7, *content,
-					     GMIME_CIPHER_CONTEXT(ctx),
-					     recipients, error);
-#else /* HAVE_GMIME_2_5_7 */
-	    g_mime_application_pkcs7_encrypt(pkcs7, *content,
-					     GMIME_CRYPTO_CONTEXT(ctx),
-					     recipients, error);
-#endif /* HAVE_GMIME_2_5_7 */
+	result = g_mime_application_pkcs7_encrypt(pkcs7, *content, recipients, always_trust, parent, error);
     }
 #endif
+    g_ptr_array_free(recipients, FALSE);
 
     /* error checking */
     if (result != 0) {
-	g_ptr_array_free(recipients, FALSE);
-	g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
 	g_object_unref(encrypted_obj);
 	return FALSE;
-    }
-
-    g_ptr_array_free(recipients, FALSE);
+    } else {
     g_object_unref(G_OBJECT(*content));
     *content = GMIME_OBJECT(encrypted_obj);
-    g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-    g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
-
     return TRUE;
+    }
 }
 
 
@@ -589,18 +362,8 @@ gboolean
 libbalsa_body_check_signature(LibBalsaMessageBody * body,
 			      gpgme_protocol_t protocol)
 {
-#if !defined(HAVE_GMIME_2_6)
-    GMimeSession *session;
-#endif                          /* HAVE_GMIME_2_6 */
-#ifndef HAVE_GMIME_2_5_7
-    GMimeCipherContext *g_mime_ctx;
-    GMimeSignatureValidity *valid;
-#else /* HAVE_GMIME_2_5_7 */
-    GMimeCryptoContext *g_mime_ctx;
-    GMimeSignatureList *valid;
-#endif /* HAVE_GMIME_2_5_7 */
-    GMimeGpgmeContext *ctx;
     GError *error = NULL;
+    GMimeGpgmeSigstat *result;
 
     /* paranoia checks */
     g_return_val_if_fail(body, FALSE);
@@ -622,56 +385,10 @@ libbalsa_body_check_signature(LibBalsaMessageBody * body,
     if (body->parts->next->sig_info)
 	g_object_unref(G_OBJECT(body->parts->next->sig_info));
 
-    /* try to create GMimeGpgMEContext */
-#if !defined(HAVE_GMIME_2_6)
-    session = g_object_new(g_mime_session_get_type(), NULL, NULL);
-    g_mime_ctx = g_mime_gpgme_context_new(session, protocol, &error);
-#else                           /* HAVE_GMIME_2_6 */
-    g_mime_ctx =
-        g_mime_gpgme_context_new(password_request_func, protocol, &error);
-#endif                          /* HAVE_GMIME_2_6 */
-    if (g_mime_ctx == NULL) {
-	if (error) {
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s: %s",
-				 _("creating a gpgme context failed"),
-				 error->message);
-	    g_error_free(error);
-	} else
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR,
-				 _("creating a gpgme context failed"));
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
-	body->parts->next->sig_info = g_mime_gpgme_sigstat_new();
-	body->parts->next->sig_info->status = GPGME_SIG_STAT_ERROR;
-	return FALSE;
-    }
-    ctx = GMIME_GPGME_CONTEXT(g_mime_ctx);
-
-    /* S/MIME uses the protocol application/pkcs7-signature, but some ancient
-       mailers, not yet knowing RFC 2633, use application/x-pkcs7-signature,
-       so tweak the context if necessary... */
-    if (protocol == GPGME_PROTOCOL_CMS) {
-	const char * cms_protocol = 
-	    g_mime_object_get_content_type_parameter(GMIME_OBJECT (body->mime_part),
-						     "protocol");
-	if (!g_ascii_strcasecmp(cms_protocol, "application/x-pkcs7-signature"))
-#ifndef HAVE_GMIME_2_5_7
-	    g_mime_ctx->sign_protocol = cms_protocol;
-#else /* HAVE_GMIME_2_5_7 */
-	    ctx->sign_protocol = cms_protocol;
-#endif /* HAVE_GMIME_2_5_7 */
-    }
-
     /* verify the signature */
-
     libbalsa_mailbox_lock_store(body->message->mailbox);
-    valid = g_mime_multipart_signed_verify(GMIME_MULTIPART_SIGNED
-					   (body->mime_part), g_mime_ctx,
-                                           &error);
-    libbalsa_mailbox_unlock_store(body->message->mailbox);
-
-    if (valid == NULL) {
+    result = g_mime_gpgme_mps_verify(GMIME_MULTIPART_SIGNED(body->mime_part), &error);
+    if (!result || result->status != GPG_ERR_NO_ERROR) {
 	if (error) {
 	    libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s: %s",
 				 _("signature verification failed"),
@@ -681,19 +398,9 @@ libbalsa_body_check_signature(LibBalsaMessageBody * body,
 	    libbalsa_information(LIBBALSA_INFORMATION_ERROR,
 				 _("signature verification failed"));
     }
-    if (ctx->sig_state) {
-	body->parts->next->sig_info = ctx->sig_state;
-	g_object_ref(G_OBJECT(body->parts->next->sig_info));
-    }
-#ifndef HAVE_GMIME_2_5_7
-    g_mime_signature_validity_free(valid);
-#else /* HAVE_GMIME_2_5_7 */
-    g_object_unref(valid);
-#endif /* HAVE_GMIME_2_5_7 */
-    g_object_unref(g_mime_ctx);
-#if !defined(HAVE_GMIME_2_6)
-    g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
+
+    body->parts->next->sig_info = result;
+    libbalsa_mailbox_unlock_store(body->message->mailbox);
     return TRUE;
 }
 
@@ -704,18 +411,14 @@ libbalsa_body_check_signature(LibBalsaMessageBody * body,
  * decrypted bodies. Otherwise, the original body is returned.
  */
 LibBalsaMessageBody *
-libbalsa_body_decrypt(LibBalsaMessageBody * body,
-		      gpgme_protocol_t protocol, GtkWindow * parent)
+libbalsa_body_decrypt(LibBalsaMessageBody *body, gpgme_protocol_t protocol, GtkWindow *parent)
 {
-#if !defined(HAVE_GMIME_2_6)
-    GMimeSession *session;
-#endif                          /* HAVE_GMIME_2_6 */
-    GMimeGpgmeContext *ctx;
     GMimeObject *mime_obj = NULL;
     GError *error = NULL;
     LibBalsaMessage *message;
+    GMimeGpgmeSigstat *sig_state = NULL;
 #ifdef HAVE_SMIME
-    gboolean smime_signed = FALSE;
+    gboolean smime_encrypted = FALSE;
 #endif
 
     /* paranoia checks */
@@ -743,97 +446,17 @@ libbalsa_body_decrypt(LibBalsaMessageBody * body,
 
 	if (!smime_type || !GMIME_IS_PART(body->mime_part))
 	    return body;
-	if (!g_ascii_strcasecmp(smime_type, "signed-data"))
-	    smime_signed = TRUE;
-	else if (!g_ascii_strcasecmp(smime_type, "enveloped-data"))
-	    smime_signed = FALSE;
-	else
-	    return body;
+	if (!g_ascii_strcasecmp(smime_type, "enveloped-data"))
+	    smime_encrypted = FALSE;
     }
 #endif
 
-#if !defined(HAVE_GMIME_2_6)
-    /* create a session and a GMimeGpgmeContext */
-    session = g_object_new(g_mime_session_get_type(), NULL, NULL);
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new(session, protocol,
-						       &error));
-#else                           /* HAVE_GMIME_2_6 */
-    /* create a GMimeGpgmeContext */
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new
-            (password_request_func, protocol, &error));
-#endif                          /* HAVE_GMIME_2_6 */
-    if (ctx == NULL) {
-	if (error) {
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s: %s",
-				 _("creating a gpgme context failed"),
-				 error->message);
-	    g_error_free(error);
-	} else
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR,
-				 _("creating a gpgme context failed"));
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
-	return body;
-    }
-
-    /* set the callback for the passphrase entry */
-    if (g_getenv("GPG_AGENT_INFO"))
-	ctx->passphrase_cb = NULL;  /* use gpg-agent */
-    else {
-	ctx->passphrase_cb = get_passphrase_cb;
-	g_object_set_data(G_OBJECT(ctx), "parent-window", parent);
-	g_object_set_data(G_OBJECT(ctx), "passphrase-info",
-			  _("Enter passphrase to decrypt message"));
-    }
-
     libbalsa_mailbox_lock_store(body->message->mailbox);
     if (protocol == GPGME_PROTOCOL_OpenPGP)
-	mime_obj =
-#ifndef HAVE_GMIME_2_5_7
-	    g_mime_multipart_encrypted_decrypt(GMIME_MULTIPART_ENCRYPTED(body->mime_part),
-					       GMIME_CIPHER_CONTEXT(ctx),
-					       &error);
-#else /* HAVE_GMIME_2_5_7 */
-	    g_mime_multipart_encrypted_decrypt(GMIME_MULTIPART_ENCRYPTED(body->mime_part),
-					       GMIME_CRYPTO_CONTEXT(ctx),
-                                               NULL,
-					       &error);
-#endif /* HAVE_GMIME_2_5_7 */
+	mime_obj = g_mime_gpgme_mpe_decrypt(GMIME_MULTIPART_ENCRYPTED(body->mime_part), &sig_state, parent, &error);
 #ifdef HAVE_SMIME
-    else if (smime_signed) {
-#ifndef HAVE_GMIME_2_5_7
-	GMimeSignatureValidity *valid;
-#else /* HAVE_GMIME_2_5_7 */
-	GMimeSignatureList *valid;
-#endif /* HAVE_GMIME_2_5_7 */
-
-	ctx->singlepart_mode = TRUE;
-#ifndef HAVE_GMIME_2_5_7
-	mime_obj =
-	    g_mime_application_pkcs7_verify(GMIME_PART(body->mime_part),
-					    &valid,
-					    GMIME_CIPHER_CONTEXT(ctx),
-					    &error);
-	g_mime_signature_validity_free(valid);
-    } else
-	mime_obj =
-	    g_mime_application_pkcs7_decrypt(GMIME_PART(body->mime_part),
-					       GMIME_CIPHER_CONTEXT(ctx),
-					       &error);
-#else /* HAVE_GMIME_2_5_7 */
-	mime_obj =
-	    g_mime_application_pkcs7_verify(GMIME_PART(body->mime_part),
-					    &valid,
-					    GMIME_CRYPTO_CONTEXT(ctx),
-					    &error);
-	g_object_unref(valid);
-    } else
-	mime_obj =
-	    g_mime_application_pkcs7_decrypt(GMIME_PART(body->mime_part),
-					       GMIME_CRYPTO_CONTEXT(ctx),
-					       &error);
-#endif /* HAVE_GMIME_2_5_7 */
+    else
+	mime_obj = g_mime_application_pkcs7_decrypt_verify(GMIME_PART(body->mime_part), &sig_state, parent, &error);
 #endif
     libbalsa_mailbox_unlock_store(body->message->mailbox);
 
@@ -848,10 +471,6 @@ libbalsa_body_decrypt(LibBalsaMessageBody * body,
 	} else
 	    libbalsa_information(LIBBALSA_INFORMATION_ERROR,
 				 _("decryption failed"));
-	g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
 	return body;
     }
     message = body->message;
@@ -863,18 +482,14 @@ libbalsa_body_decrypt(LibBalsaMessageBody * body,
 	body->was_encrypted = TRUE;
 #ifdef HAVE_SMIME
     else
-	body->was_encrypted = !smime_signed;
+	body->was_encrypted = smime_encrypted;
 #endif
 
     libbalsa_message_body_set_mime_body(body, mime_obj);
-    if (ctx->sig_state && ctx->sig_state->status != GPG_ERR_NOT_SIGNED) {
-	g_object_ref(ctx->sig_state);
-	body->sig_info = ctx->sig_state;
-    }
-    g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-    g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
+    if (sig_state && sig_state->status != GPG_ERR_NOT_SIGNED)
+	body->sig_info = sig_state;
+    else
+	g_object_unref(G_OBJECT(sig_state));
 
     return body;
 }
@@ -883,14 +498,9 @@ libbalsa_body_decrypt(LibBalsaMessageBody * body,
 
 /* routines dealing with RFC2440 */
 gboolean
-libbalsa_rfc2440_sign_encrypt(GMimePart * part, const gchar * sign_for,
-			      GList * encrypt_for, gboolean always_trust,
-			      GtkWindow * parent, GError ** error)
+libbalsa_rfc2440_sign_encrypt(GMimePart *part, const gchar *sign_for, GList *encrypt_for, gboolean always_trust,
+			      GtkWindow *parent, GError **error)
 {
-#if !defined(HAVE_GMIME_2_6)
-    GMimeSession *session;
-#endif                          /* HAVE_GMIME_2_6 */
-    GMimeGpgmeContext *ctx;
     GPtrArray *recipients;
     gint result;
 
@@ -902,42 +512,6 @@ libbalsa_rfc2440_sign_encrypt(GMimePart * part, const gchar * sign_for,
     if (gpg_updates_trustdb())
 	return FALSE;
 
-#if !defined(HAVE_GMIME_2_6)
-    /* create a session and a GMimeGpgmeContext */
-    session = g_object_new(g_mime_session_get_type(), NULL, NULL);
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new(session,
-						       GPGME_PROTOCOL_OpenPGP,
-						       error));
-    if (ctx == NULL) {
-	g_object_unref(session);
-#else                           /* HAVE_GMIME_2_6 */
-    /* create a GMimeGpgmeContext */
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new
-            (password_request_func, GPGME_PROTOCOL_OpenPGP, error));
-    if (ctx == NULL)
-#endif                          /* HAVE_GMIME_2_6 */
-	return FALSE;
-#if !defined(HAVE_GMIME_2_6)
-    }
-#endif                          /* HAVE_GMIME_2_6 */
-
-    /* set the callback for the key selection and the passphrase */
-    if (sign_for) {
-	if (g_getenv("GPG_AGENT_INFO"))
-	    ctx->passphrase_cb = NULL;  /* use gpg-agent */
-	else {
-	    ctx->passphrase_cb = get_passphrase_cb;
-	    g_object_set_data(G_OBJECT(ctx), "passphrase-info",
-			      _
-			      ("Enter passphrase to unlock the secret key for signing"));
-	}
-    }
-    ctx->key_select_cb = select_key_from_list;
-    if (!always_trust)
-	ctx->key_trust_cb = accept_low_trust_key;
-    ctx->always_trust_uid = always_trust;
-    g_object_set_data(G_OBJECT(ctx), "parent-window", parent);
-
     /* convert the key list to a GPtrArray */
     if (encrypt_for) {
 	recipients = g_ptr_array_new();
@@ -949,16 +523,10 @@ libbalsa_rfc2440_sign_encrypt(GMimePart * part, const gchar * sign_for,
 	recipients = NULL;
 
     /* sign and/or encrypt */
-    result =
-	g_mime_part_rfc2440_sign_encrypt(part, ctx, recipients, sign_for,
-					 error);
+    result = g_mime_part_rfc2440_sign_encrypt(part, sign_for, recipients, always_trust, parent, error);
     /* clean up */
     if (recipients)
 	g_ptr_array_free(recipients, FALSE);
-    g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-    g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
     return (result == 0) ? TRUE : FALSE;
 }
 
@@ -970,15 +538,7 @@ libbalsa_rfc2440_sign_encrypt(GMimePart * part, const gchar * sign_for,
 gpgme_error_t
 libbalsa_rfc2440_verify(GMimePart * part, GMimeGpgmeSigstat ** sig_info)
 {
-#if !defined(HAVE_GMIME_2_6)
-    GMimeSession *session;
-#endif                          /* HAVE_GMIME_2_6 */
-    GMimeGpgmeContext *ctx;
-#ifndef HAVE_GMIME_2_5_7
-    GMimeSignatureValidity *valid;
-#else /* HAVE_GMIME_2_5_7 */
-    GMimeSignatureList *valid;
-#endif /* HAVE_GMIME_2_5_7 */
+    GMimeGpgmeSigstat *result;
     GError *error = NULL;
     gpgme_error_t retval;
 
@@ -995,36 +555,9 @@ libbalsa_rfc2440_verify(GMimePart * part, GMimeGpgmeSigstat ** sig_info)
     if (gpg_updates_trustdb())
 	return GPG_ERR_TRY_AGAIN;
 
-#if !defined(HAVE_GMIME_2_6)
-    /* create a session and a GMimeGpgmeContext */
-    session = g_object_new(g_mime_session_get_type(), NULL, NULL);
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new(session,
-						       GPGME_PROTOCOL_OpenPGP,
-						       &error));
-#else                           /* HAVE_GMIME_2_6 */
-    /* create a GMimeGpgmeContext */
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new
-            (password_request_func, GPGME_PROTOCOL_OpenPGP, &error));
-#endif                          /* HAVE_GMIME_2_6 */
-    if (ctx == NULL) {
-	if (error) {
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s: %s",
-				 _("creating a gpgme context failed"),
-				 error->message);
-	    g_error_free(error);
-	} else
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR,
-				 _("creating a gpgme context failed"));
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
-	return FALSE;
-    }
-
     /* verify */
-    valid = g_mime_part_rfc2440_verify(part, ctx, &error);
-
-    if (valid == NULL) {
+    result = g_mime_part_rfc2440_verify(part, &error);
+    if (!result || result->status != GPG_ERR_NO_ERROR) {
 	if (error) {
 	    libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s: %s",
 				 _("signature verification failed"),
@@ -1036,30 +569,16 @@ libbalsa_rfc2440_verify(GMimePart * part, GMimeGpgmeSigstat ** sig_info)
 				 _("signature verification failed"));
 	    retval = GPG_ERR_GENERAL;
 	}
-	g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
-	return retval;
-    }
+    } else
+	retval = result->status;
 
     /* return the signature info if requested */
-    if (sig_info) {
-	g_object_ref(ctx->sig_state);
-	*sig_info = ctx->sig_state;
+    if (result) {
+	if (sig_info)
+	    *sig_info = result;
+	else
+	    g_object_unref(G_OBJECT(result));
     }
-
-    /* clean up */
-#ifndef HAVE_GMIME_2_5_7
-    g_mime_signature_validity_free(valid);
-#else /* HAVE_GMIME_2_5_7 */
-    g_object_unref(valid);
-#endif /* HAVE_GMIME_2_5_7 */
-    retval = ctx->sig_state->status;
-    g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-    g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
     return retval;
 }
 
@@ -1073,11 +592,8 @@ gpgme_error_t
 libbalsa_rfc2440_decrypt(GMimePart * part, GMimeGpgmeSigstat ** sig_info,
 			 GtkWindow * parent)
 {
-#if !defined(HAVE_GMIME_2_6)
-    GMimeSession *session;
-#endif                          /* HAVE_GMIME_2_6 */
-    GMimeGpgmeContext *ctx;
     GError *error = NULL;
+    GMimeGpgmeSigstat *result;
     gpgme_error_t retval;
 
     /* paranoia checks */
@@ -1093,44 +609,11 @@ libbalsa_rfc2440_decrypt(GMimePart * part, GMimeGpgmeSigstat ** sig_info,
     if (gpg_updates_trustdb())
 	return GPG_ERR_TRY_AGAIN;
 
-#if !defined(HAVE_GMIME_2_6)
-    /* create a session and a GMimeGpgmeContext */
-    session = g_object_new(g_mime_session_get_type(), NULL, NULL);
-    ctx =
-	GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new
-			    (session, GPGME_PROTOCOL_OpenPGP, &error));
-#else                           /* HAVE_GMIME_2_6 */
-    /* create a GMimeGpgmeContext */
-    ctx = GMIME_GPGME_CONTEXT(g_mime_gpgme_context_new
-            (password_request_func, GPGME_PROTOCOL_OpenPGP, &error));
-#endif                          /* HAVE_GMIME_2_6 */
-    if (ctx == NULL) {
-	if (error) {
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s: %s",
-				 _("creating a gpgme context failed"),
-				 error->message);
-	    g_error_free(error);
-	} else
-	    libbalsa_information(LIBBALSA_INFORMATION_ERROR,
-				 _("creating a gpgme context failed"));
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
-	return GPG_ERR_GENERAL;
-    }
-
-    /* set the callback for the passphrase */
-    if (g_getenv("GPG_AGENT_INFO"))
-	ctx->passphrase_cb = NULL;  /* use gpg-agent */
-    else {
-	ctx->passphrase_cb = get_passphrase_cb;
-	g_object_set_data(G_OBJECT(ctx), "passphrase-info",
-			  _("Enter passphrase to decrypt message"));
-	g_object_set_data(G_OBJECT(ctx), "parent-window", parent);
-    }
+    // g_object_set_data(G_OBJECT(ctx), "parent-window", parent); FIXME - pass downstream
 
     /* decrypt */
-    if (g_mime_part_rfc2440_decrypt(part, ctx, &error) == NULL) {
+    result = g_mime_part_rfc2440_decrypt(part, parent, &error);
+    if (result == NULL) {
 	if (error) {
 	    if (error->code != GPG_ERR_CANCELED)
 		libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s: %s",
@@ -1144,28 +627,18 @@ libbalsa_rfc2440_decrypt(GMimePart * part, GMimeGpgmeSigstat ** sig_info,
 				 ("decryption and signature verification failed"));
 	    retval = GPG_ERR_GENERAL;
 	}
-	g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-	g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
 	return retval;
-    }
+    } else
+	retval = result->status;
 
-    retval = GPG_ERR_NO_ERROR;
-    if (ctx->sig_state) {
-	retval = ctx->sig_state->status;
-	/* return the signature info if requested & available */
-	if (sig_info && ctx->sig_state->status != GPG_ERR_NOT_SIGNED) {
-	    g_object_ref(ctx->sig_state);
-	    *sig_info = ctx->sig_state;
-	}
+    /* return the signature info if requested */
+    if (result) {
+	if (sig_info && result->status != GPG_ERR_NOT_SIGNED)
+	    *sig_info = result;
+	else
+	    g_object_unref(G_OBJECT(result));
     }
 
-    /* clean up */
-    g_object_unref(ctx);
-#if !defined(HAVE_GMIME_2_6)
-    g_object_unref(session);
-#endif                          /* HAVE_GMIME_2_6 */
     return retval;
 }
 
@@ -1204,6 +677,8 @@ libbalsa_gpgme_sig_stat_to_gchar(gpgme_error_t stat)
 	return _("An error prevented the signature verification.");
     }
 }
+
+
 const gchar *
 libbalsa_gpgme_validity_to_gchar(gpgme_validity_t validity)
 {
@@ -1224,6 +699,30 @@ libbalsa_gpgme_validity_to_gchar(gpgme_validity_t validity)
 	return _("bad validity");
     }
 }
+
+
+const gchar *
+libbalsa_gpgme_validity_to_gchar_short(gpgme_validity_t validity)
+{
+    switch (validity) {
+    case GPGME_VALIDITY_UNKNOWN:
+	return _("unknown");
+    case GPGME_VALIDITY_UNDEFINED:
+	return _("undefined");
+    case GPGME_VALIDITY_NEVER:
+	return _("never");
+    case GPGME_VALIDITY_MARGINAL:
+	return _("marginal");
+    case GPGME_VALIDITY_FULL:
+	return _("full");
+    case GPGME_VALIDITY_ULTIMATE:
+	return _("ultimate");
+    default:
+	return _("bad validity");
+    }
+}
+
+
 const gchar *
 libbalsa_gpgme_sig_protocol_name(gpgme_protocol_t protocol)
 {
@@ -1237,14 +736,18 @@ libbalsa_gpgme_sig_protocol_name(gpgme_protocol_t protocol)
     }
 }
 
-#define APPEND_TIMET(str,fmt,t)						\
-    do {                                                                \
-        if (t) {                                                        \
-            gchar * _tbuf = libbalsa_date_to_utf8(&t, date_string);     \
-            g_string_append_printf(str, fmt, _tbuf);      \
-            g_free(_tbuf);                                              \
-        }                                                               \
-    } while (0)
+static inline void
+append_time_t(GString *str, const gchar *format, time_t *when,
+              const gchar * date_string)
+{
+    if (*when != (time_t) 0) {
+        gchar *tbuf = libbalsa_date_to_utf8(when, date_string);
+        g_string_append_printf(str, format, tbuf);
+        g_free(tbuf);
+    } else {
+        g_string_append_printf(str, format, _("never"));
+    }
+}
 
 gchar *
 libbalsa_signature_info_to_gchar(GMimeGpgmeSigstat * info,
@@ -1259,74 +762,124 @@ libbalsa_signature_info_to_gchar(GMimeGpgmeSigstat * info,
     msg =
 	g_string_append(msg,
 			libbalsa_gpgme_sig_stat_to_gchar(info->status));
-    if (info->sign_uid && strlen(info->sign_uid))
-	g_string_append_printf(msg, _("\nUser ID: %s"), info->sign_uid);
-
-    else if (info->sign_name && strlen(info->sign_name)) {
-	g_string_append_printf(msg, _("\nSigned by: %s"), info->sign_name);
-	if (info->sign_email && strlen(info->sign_email))
-	    g_string_append_printf(msg, " <%s>", info->sign_email);
-    } else if (info->sign_email && strlen(info->sign_email))
-	g_string_append_printf(msg, _("\nMail address: %s"),
-			       info->sign_email);
-    APPEND_TIMET(msg, _("\nSigned on: %s"), info->sign_time);
-    g_string_append_printf(msg, _("\nUser ID validity: %s"),
+    g_string_append_printf(msg, _("\nSignature validity: %s"),
 			   libbalsa_gpgme_validity_to_gchar(info->
 							    validity));
-    if (info->protocol == GPGME_PROTOCOL_OpenPGP)
+    append_time_t(msg, _("\nSigned on: %s"), &info->sign_time, date_string);
+    if (info->protocol == GPGME_PROTOCOL_OpenPGP && info->key)
 	g_string_append_printf(msg, _("\nKey owner trust: %s"),
 			       libbalsa_gpgme_validity_to_gchar_short
-			       (info->trust));
+			       (info->key->owner_trust));
     if (info->fingerprint)
 	g_string_append_printf(msg, _("\nKey fingerprint: %s"),
 			       info->fingerprint);
-    /* Subkey creation date */
-    APPEND_TIMET(msg, _("\nSubkey created on: %s"), info->key_created);
-    /* Subkey expiration date */
-    APPEND_TIMET(msg, _("\nSubkey expires on: %s"), info->key_expires);
-    if (info->key_revoked || info->key_expired || info->key_disabled ||
-       info->key_invalid) {
+
+    /* add key information */
+    if (info->key) {
+        gpgme_user_id_t uid;
+        gpgme_subkey_t subkey;
+
+        /* user ID's */
+        if ((uid = info->key->uids)) {
+            gchar *lead_text;
+
+            uid = info->key->uids;
+            if (uid->next) {
+        	msg = g_string_append(msg, _("\nUser ID's:"));
+        	lead_text = "\n\342\200\242";
+            } else {
+        	msg = g_string_append(msg, _("\nUser ID:"));
+        	lead_text = "";
+            }
+
+            /* Note: there is no way to determine which user id has been used
+             * to create the signature.  A broken client may even use an
+             * invalid and/or revoked one.  We therefore add all to the
+             * result. */
+            while (uid) {
+        	msg = g_string_append(msg, lead_text);
+        	if (uid->revoked)
+        	    msg = g_string_append(msg, _(" [Revoked]"));
+        	if (uid->invalid)
+        	    msg = g_string_append(msg, _(" [Invalid]"));
+
+        	if (uid->uid && *(uid->uid)) {
+        	    gchar *uid_readable =
+        	    	libbalsa_cert_subject_readable(uid->uid);
+        	    g_string_append_printf(msg, " %s", uid_readable);
+        	    g_free(uid_readable);
+        	} else {
+        	    if (uid->name && *(uid->name))
+        		g_string_append_printf(msg, " %s", uid->name);
+        	    if (uid->email && *(uid->email))
+        		g_string_append_printf(msg, " <%s>", uid->email);
+        	    if (uid->comment && *(uid->comment))
+        		g_string_append_printf(msg, " (%s)", uid->comment);
+        	}
+
+        	uid = uid->next;
+            }
+        }
+
+        /* subkey */
+        if ((subkey = info->key->subkeys)) {
+            /* find the one which can sign */
+            while (subkey && !subkey->can_sign)
+        	subkey = subkey->next;
+
+            if (subkey) {
+        	append_time_t(msg, _("\nSubkey created on: %s"),
+        		      &subkey->timestamp, date_string);
+        	append_time_t(msg, _("\nSubkey expires on: %s"),
+        		      &subkey->expires, date_string);
+        	if (subkey->revoked || subkey->expired || subkey->disabled ||
+        	    subkey->invalid) {
        GString * attrs = g_string_new("");
        int count = 0;
 
-       if (info->key_revoked) {
+        	    if (subkey->revoked) {
            count++;
            attrs = g_string_append(attrs, _(" revoked"));
        }
-       if (info->key_expired) {
+        	    if (subkey->expired) {
            if (count++)
                attrs = g_string_append_c(attrs, ',');
            attrs = g_string_append(attrs, _(" expired"));
        }
-       if (info->key_disabled) {
+        	    if (subkey->disabled) {
            if (count)
                attrs = g_string_append_c(attrs, ',');
            attrs = g_string_append(attrs, _(" disabled"));
        }
-       if (info->key_invalid) {
+        	    if (subkey->invalid) {
            if (count)
                attrs = g_string_append_c(attrs, ',');
            attrs = g_string_append(attrs, _(" invalid"));
        }
-       /* ngettext: string begins with a single space, so no space after
-        * the colon is correct punctuation (in English). */
+        	    /* ngettext: string begins with a single space, so no space
+        	     * after the colon is correct punctuation (in English). */
        g_string_append_printf(msg, ngettext("\nSubkey attribute:%s",
                                             "\nSubkey attributes:%s",
                                             count),
                               attrs->str);
        g_string_free(attrs, TRUE);
     }
-    if (info->issuer_name) {
-	gchar * issuer = fix_EMail_info(g_strdup(info->issuer_name));
-
-	g_string_append_printf(msg, _("\nIssuer name: %s"), issuer);
-	g_free(issuer);
+            }
+        }
+
+        if (info->key->issuer_name) {
+            gchar *issuer_name =
+        	libbalsa_cert_subject_readable(info->key->issuer_name);
+            g_string_append_printf(msg, _("\nIssuer name: %s"), issuer_name);
+            g_free(issuer_name);
     }
-    if (info->issuer_serial)
+        if (info->key->issuer_serial)
 	g_string_append_printf(msg, _("\nIssuer serial number: %s"),
-			       info->issuer_serial);
-    if (info->chain_id)
-	g_string_append_printf(msg, _("\nChain ID: %s"), info->chain_id);
+				   info->key->issuer_serial);
+        if (info->key->chain_id)
+            g_string_append_printf(msg, _("\nChain ID: %s"), info->key->chain_id);
+    }
+
     retval = msg->str;
     g_string_free(msg, FALSE);
     return retval;
@@ -1462,489 +1015,6 @@ check_gpg_child(gpointer data)
 /* ==== local stuff ======================================================== */
 
 
-static const gchar *
-libbalsa_gpgme_validity_to_gchar_short(gpgme_validity_t validity)
-{
-    switch (validity) {
-    case GPGME_VALIDITY_UNKNOWN:
-	return _("unknown");
-    case GPGME_VALIDITY_UNDEFINED:
-	return _("undefined");
-    case GPGME_VALIDITY_NEVER:
-	return _("never");
-    case GPGME_VALIDITY_MARGINAL:
-	return _("marginal");
-    case GPGME_VALIDITY_FULL:
-	return _("full");
-    case GPGME_VALIDITY_ULTIMATE:
-	return _("ultimate");
-    default:
-	return _("bad validity");
-    }
-}
-
-
-#define OID_EMAIL       "1.2.840.113549.1.9.1=#"
-#define OID_EMAIL_LEN   22
-static gchar *
-fix_EMail_info(gchar * str)
-{
-    gchar *p;
-    GString *result;
-
-    /* check for any EMail info */
-    p = strstr(str, OID_EMAIL);
-    if (!p)
-	return str;
-
-    *p = '\0';
-    p += OID_EMAIL_LEN;
-    result = g_string_new(str);
-    while (p) {
-	gchar *next;
-
-	result = g_string_append(result, "EMail=");
-	/* convert the info from hex until we reach some other char */
-	while (g_ascii_isxdigit(*p)) {
-	    gchar c = g_ascii_xdigit_value(*p++) << 4;
-
-	    if (g_ascii_isxdigit(*p))
-		result =
-		    g_string_append_c(result, c + g_ascii_xdigit_value(*p++));
-	}
-	
-	/* find more */
-	next = strstr(p, OID_EMAIL);
-	if (next) {
-	    *next = '\0';
-	    next += OID_EMAIL_LEN;
-	}
-	result = g_string_append(result, p);
-	p = next;
-    }
-    g_free(str);
-    p = result->str;
-    g_string_free(result, FALSE);
-    return p;
-}
-
-
-/* stuff to get a key fingerprint from a selection list */
-enum {
-    GPG_KEY_USER_ID_COLUMN = 0,
-    GPG_KEY_ID_COLUMN,
-    GPG_KEY_LENGTH_COLUMN,
-    GPG_KEY_VALIDITY_COLUMN,
-    GPG_KEY_PTR_COLUMN,
-    GPG_KEY_NUM_COLUMNS
-};
-
-static gchar *col_titles[] =
-    { N_("User ID"), N_("Key ID"), N_("Length"), N_("Validity") };
-
-/* callback function if a new row is selected in the list */
-static void
-key_selection_changed_cb(GtkTreeSelection * selection, gpgme_key_t * key)
-{
-    GtkTreeIter iter;
-    GtkTreeModel *model;
-
-    if (gtk_tree_selection_get_selected(selection, &model, &iter))
-	gtk_tree_model_get(model, &iter, GPG_KEY_PTR_COLUMN, key, -1);
-}
-
-
-/*
- * Select a key for the mail address for_address from the gpgme_key_t's in keys
- * and return either the selected key or NULL if the dialog was cancelled.
- * secret_only controls the dialog message.
- */
-static gpgme_key_t
-select_key_from_list(const gchar * name, gboolean is_secret,
-		     GMimeGpgmeContext * ctx, GList * keys)
-{
-    GtkWidget *dialog;
-    GtkWidget *vbox;
-    GtkWidget *label;
-    GtkWidget *scrolled_window;
-    GtkWidget *tree_view;
-    GtkTreeStore *model;
-    GtkTreeSelection *selection;
-    GtkTreeIter iter;
-    gint i, last_col;
-    gchar *prompt;
-    gchar *upcase_name;
-    gpgme_protocol_t protocol;
-    GtkWindow *parent;
-    gpgme_key_t use_key = NULL;
-
-    g_return_val_if_fail(ctx != NULL, NULL);
-    g_return_val_if_fail(keys != NULL, NULL);
-    protocol = gpgme_get_protocol(ctx->gpgme_ctx);
-    parent = GTK_WINDOW(g_object_get_data(G_OBJECT(ctx), "parent-window"));
-
-    /* FIXME: create dialog according to the Gnome HIG */
-    dialog = gtk_dialog_new_with_buttons(_("Select key"),
-					 parent,
-					 GTK_DIALOG_DESTROY_WITH_PARENT,
-					 GTK_STOCK_OK, GTK_RESPONSE_OK,
-					 GTK_STOCK_CANCEL,
-					 GTK_RESPONSE_CANCEL, NULL);
-#if HAVE_MACOSX_DESKTOP
-    libbalsa_macosx_menu_for_parent(dialog, parent);
-#endif
-    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
-    gtk_container_add(GTK_CONTAINER
-                      (gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
-                      vbox);
-    gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
-    if (is_secret)
-	prompt =
-	    g_strdup_printf(_("Select the private key for the signer %s"),
-			    name);
-    else
-	prompt = g_strdup_printf(_
-				 ("Select the public key for the recipient %s"),
-				 name);
-    label = gtk_label_new(prompt);
-    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-    g_free(prompt);
-    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
-
-    scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW
-					(scrolled_window),
-					GTK_SHADOW_ETCHED_IN);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
-				   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-    gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
-
-    model =
-	gtk_tree_store_new(GPG_KEY_NUM_COLUMNS,
-			   G_TYPE_STRING,   /* user ID */
-			   G_TYPE_STRING,   /* key ID */
-			   G_TYPE_INT,      /* length */
-			   G_TYPE_STRING,   /* validity (gpg encrypt only) */
-			   G_TYPE_POINTER); /* key */
-
-    tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
-    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
-    gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
-    g_signal_connect(G_OBJECT(selection), "changed",
-		     G_CALLBACK(key_selection_changed_cb), &use_key);
-
-    /* add the keys */
-    upcase_name = g_ascii_strup(name, -1);
-    while (keys) {
-	gpgme_key_t key = (gpgme_key_t) keys->data;
-	gpgme_subkey_t subkey = key->subkeys;
-	gpgme_user_id_t uid = key->uids;
-	gchar *uid_info = NULL;
-	gboolean uid_found;
-
-	/* find the relevant subkey */
-	while (subkey && ((is_secret && !subkey->can_sign) ||
-			  (!is_secret && !subkey->can_encrypt)))
-	    subkey = subkey->next;
-
-	/* find the relevant uid */
-	uid_found = FALSE;
-	while (uid && !uid_found) {
-	    g_free(uid_info);
-	    uid_info = fix_EMail_info(g_strdup(uid->uid));
-
-	    /* check the email field which may or may not be present */
-	    if (uid->email && !g_ascii_strcasecmp(uid->email, name))
-		uid_found = TRUE;
-	    else {
-		/* no email or no match, check the uid */
-		gchar * upcase_uid = g_ascii_strup(uid_info, -1);
-		
-		if (strstr(upcase_uid, upcase_name))
-		    uid_found = TRUE;
-		else
-		    uid = uid->next;
-		g_free(upcase_uid);
-	    }
-	}
-
-	/* append the element */
-	if (subkey && uid) {
-	    gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
-	    gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
-			       GPG_KEY_USER_ID_COLUMN, uid_info,
-			       GPG_KEY_ID_COLUMN, subkey->keyid,
-			       GPG_KEY_LENGTH_COLUMN, subkey->length,
-			       GPG_KEY_VALIDITY_COLUMN,
-			       libbalsa_gpgme_validity_to_gchar_short
-			       (uid->validity),
-			       GPG_KEY_PTR_COLUMN, key,
-			       -1);
-	}
-	g_free(uid_info);
-	keys = g_list_next(keys);
-    }
-    g_free(upcase_name);
-
-    g_object_unref(G_OBJECT(model));
-    /* show the validity only if we are asking for a gpg public key */
-    last_col = (protocol == GPGME_PROTOCOL_CMS || is_secret) ?
-	GPG_KEY_LENGTH_COLUMN :	GPG_KEY_VALIDITY_COLUMN;
-    for (i = 0; i <= last_col; i++) {
-	GtkCellRenderer *renderer;
-	GtkTreeViewColumn *column;
-
-	renderer = gtk_cell_renderer_text_new();
-	column =
-	    gtk_tree_view_column_new_with_attributes(_(col_titles[i]),
-						     renderer, "text", i,
-						     NULL);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
-	gtk_tree_view_column_set_resizable(column, TRUE);
-    }
-
-    gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view);
-    gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
-    gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
-
-    if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK)
-	use_key = NULL;
-    gtk_widget_destroy(dialog);
-
-    return use_key;
-}
-
-
-/*
- * Display a dialog to select whether a key with a low trust level shall be accepted
- */
-static gboolean
-accept_low_trust_key(const gchar * name, gpgme_user_id_t uid,
-		     GMimeGpgmeContext * ctx)
-{
-    GtkWidget *dialog;
-    GtkWindow *parent;
-    gint result;
-    gchar *message1;
-    gchar *message2;
-
-    /* paranoia checks */
-    g_return_val_if_fail(ctx != NULL, FALSE);
-    g_return_val_if_fail(uid != NULL, FALSE);
-    parent = GTK_WINDOW(g_object_get_data(G_OBJECT(ctx), "parent-window"));
-    
-    /* build the message */
-    message1 =
-	g_strdup_printf(_("Insufficient trust for recipient %s"), name);
-    message2 =
-	g_strdup_printf(_("The validity of the key with user ID \"%s\" is \"%s\"."),
-			uid->uid,
-			libbalsa_gpgme_validity_to_gchar_short(uid->validity));
-    dialog = 
-	gtk_message_dialog_new_with_markup(parent,
-					   GTK_DIALOG_DESTROY_WITH_PARENT,
-					   GTK_MESSAGE_WARNING,
-					   GTK_BUTTONS_YES_NO,
-					   "<b>%s</b>\n\n%s\n%s",
-					   message1,
-					   message2,
-					   _("Use this key anyway?"));
-#if HAVE_MACOSX_DESKTOP
-    libbalsa_macosx_menu_for_parent(dialog, parent);
-#endif
-			      
-    /* ask the user */
-    result = gtk_dialog_run(GTK_DIALOG(dialog));
-    gtk_widget_destroy(dialog);
-
-    return result == GTK_RESPONSE_YES;
-}
-
-
-/*
- * display a dialog to read the passphrase
- */
-static gchar *
-get_passphrase_real(GMimeGpgmeContext * ctx, const gchar * uid_hint,
-		    int prev_was_bad)
-{
-    static GdkPixbuf *padlock_keyhole = NULL;
-    GtkWidget *dialog, *entry, *vbox, *hbox;
-    gchar *prompt, *passwd;
-    const gchar *title =
-	g_object_get_data(G_OBJECT(ctx), "passphrase-title");
-    GtkWindow *parent = g_object_get_data(G_OBJECT(ctx), "parent-window");
-
-    /* FIXME: create dialog according to the Gnome HIG */
-    dialog = gtk_dialog_new_with_buttons(title, parent,
-					 GTK_DIALOG_DESTROY_WITH_PARENT,
-					 GTK_STOCK_OK, GTK_RESPONSE_OK,
-					 GTK_STOCK_CANCEL,
-					 GTK_RESPONSE_CANCEL, NULL);
-#if HAVE_MACOSX_DESKTOP
-    libbalsa_macosx_menu_for_parent(dialog, parent);
-#endif
-    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
-    gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
-    gtk_container_add(GTK_CONTAINER
-                      (gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
-                      hbox);
-
-    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
-    gtk_container_add(GTK_CONTAINER(hbox), vbox);
-    if (!padlock_keyhole)
-	padlock_keyhole =
-	    gdk_pixbuf_new_from_xpm_data(padlock_keyhole_xpm);
-    gtk_box_pack_start(GTK_BOX(vbox),
-		       gtk_image_new_from_pixbuf(padlock_keyhole), FALSE,
-		       FALSE, 0);
-    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
-    gtk_container_add(GTK_CONTAINER(hbox), vbox);
-    if (prev_was_bad)
-	prompt =
-	    g_strdup_printf(_
-			    ("The passphrase for this key was bad, please try again!\n\nKey: %s"),
-			    uid_hint);
-    else
-	prompt =
-	    g_strdup_printf(_
-			    ("Please enter the passphrase for the secret key!\n\nKey: %s"),
-			    uid_hint);
-    gtk_container_add(GTK_CONTAINER(vbox), gtk_label_new(prompt));
-    g_free(prompt);
-    entry = gtk_entry_new();
-    gtk_container_add(GTK_CONTAINER(vbox), entry);
-
-    gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
-    gtk_entry_set_width_chars(GTK_ENTRY(entry), 40);
-    gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-
-    gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
-    gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
-    gtk_widget_grab_focus(entry);
-    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
-	passwd = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
-    else
-	passwd = NULL;
-
-    gtk_widget_destroy(dialog);
-
-    return passwd;
-}
-
-
-#ifdef BALSA_USE_THREADS
-/* FIXME: is this really necessary? */
-typedef struct {
-    pthread_cond_t cond;
-    GMimeGpgmeContext *ctx;
-    const gchar *desc;
-    gint was_bad;
-    gchar *res;
-} AskPassphraseData;
-
-/* get_passphrase_idle:
-   called in MT mode by the main thread.
- */
-static gboolean
-get_passphrase_idle(gpointer data)
-{
-    AskPassphraseData *apd = (AskPassphraseData *) data;
-    gdk_threads_enter();
-    apd->res = get_passphrase_real(apd->ctx, apd->desc, apd->was_bad);
-    gdk_threads_leave();
-    pthread_cond_signal(&apd->cond);
-    return FALSE;
-}
-#endif
-
-
-/*
- * Helper function: overwrite a sting in memory with random data
- */
-static inline void
-wipe_string(gchar * password)
-{
-    while (*password)
-	*password++ = random();
-}
-
-
-/*
- * Called by gpgme to get the passphrase for a key.
- */
-static gpgme_error_t
-get_passphrase_cb(void *opaque, const char *uid_hint,
-		  const char *passph_info, int prev_was_bad, int fd)
-{
-    GMimeGpgmeContext *context;
-    gchar *passwd = NULL;
-    int foo, bar;
-
-    if (!opaque || !GMIME_IS_GPGME_CONTEXT(opaque)) {
-	foo = write(fd, "\n", 1);
-	return foo > 0 ? GPG_ERR_USER_1 : GPG_ERR_EIO;
-    }
-    context = GMIME_GPGME_CONTEXT(opaque);
-
-#ifdef ENABLE_PCACHE
-    if (!pcache)
-	pcache = init_pcache();
-
-    /* check if we have the passphrase already cached... */
-    if ((passwd = check_cache(pcache, uid_hint, prev_was_bad))) {
-	foo = write(fd, passwd, strlen(passwd));
-	bar = write(fd, "\n", 1);
-	wipe_string(passwd);
-	g_free(passwd);
-	return foo > 0 && bar > 0 ? GPG_ERR_NO_ERROR : GPG_ERR_EIO;
-    }
-#endif
-
-#ifdef BALSA_USE_THREADS
-    if (!libbalsa_am_i_subthread())
-#ifdef ENABLE_PCACHE
-	passwd =
-	    get_passphrase_real(context, uid_hint, prev_was_bad, pcache);
-
-#else
-	passwd = get_passphrase_real(context, uid_hint, prev_was_bad);
-#endif
-    else {
-	static pthread_mutex_t get_passphrase_lock =
-	    PTHREAD_MUTEX_INITIALIZER;
-	AskPassphraseData apd;
-
-	pthread_mutex_lock(&get_passphrase_lock);
-	pthread_cond_init(&apd.cond, NULL);
-	apd.ctx = context;
-	apd.desc = uid_hint;
-	apd.was_bad = prev_was_bad;
-	g_idle_add(get_passphrase_idle, &apd);
-	pthread_cond_wait(&apd.cond, &get_passphrase_lock);
-
-	pthread_cond_destroy(&apd.cond);
-	pthread_mutex_unlock(&get_passphrase_lock);
-	passwd = apd.res;
-    }
-#else
-    passwd = get_passphrase_real(context, uid_hint, prev_was_bad);
-#endif				/* BALSA_USE_THREADS */
-
-    if (!passwd) {
-	foo = write(fd, "\n", 1);
-	return foo > 0 ? GPG_ERR_CANCELED : GPG_ERR_EIO;
-    }
-
-    /* send the passphrase and erase the string */
-    foo = write(fd, passwd, strlen(passwd));
-    wipe_string(passwd);
-    g_free(passwd);
-    bar = write(fd, "\n", 1);
-    return foo > 0 && bar > 0 ? GPG_ERR_NO_ERROR : GPG_ERR_EIO;
-}
-
-
 /*
  * return TRUE is gpg is currently updating the trust database (indicated by
  * the file ~/.gnupg/trustdb.gpg.lock)
diff --git a/libbalsa/rfc3156.h b/libbalsa/rfc3156.h
index 4f4be8c..1331b33 100644
--- a/libbalsa/rfc3156.h
+++ b/libbalsa/rfc3156.h
@@ -37,7 +37,7 @@
 #include <gpgme.h>
 #include "libbalsa.h"
 #include "misc.h"
-#include "gmime-gpgme-context.h"
+#include "gmime-gpgme-signature.h"
 
 
 /* bits to define the protection mode: signed or encrypted */
@@ -60,8 +60,6 @@
 #define GPG_ERR_NOT_SIGNED         GPG_ERR_USER_16
 
 
-gboolean libbalsa_check_crypto_engine(gpgme_protocol_t protocol);
-
 gint libbalsa_message_body_protection(LibBalsaMessageBody * body);
 gboolean libbalsa_can_encrypt_for_all(InternetAddressList * recipients,
 				      gpgme_protocol_t protocol);
@@ -108,6 +106,7 @@ gpgme_error_t libbalsa_rfc2440_decrypt(GMimePart * part,
 const gchar *libbalsa_gpgme_sig_protocol_name(gpgme_protocol_t protocol);
 const gchar *libbalsa_gpgme_sig_stat_to_gchar(gpgme_error_t stat);
 const gchar *libbalsa_gpgme_validity_to_gchar(gpgme_validity_t validity);
+const gchar *libbalsa_gpgme_validity_to_gchar_short(gpgme_validity_t validity);
 gchar *libbalsa_signature_info_to_gchar(GMimeGpgmeSigstat * info,
 					const gchar * date_string);
 
diff --git a/src/balsa-message.c b/src/balsa-message.c
index 1bdbf2f..f6b34f4 100644
--- a/src/balsa-message.c
+++ b/src/balsa-message.c
@@ -3037,7 +3037,7 @@ libbalsa_msg_part_2440(LibBalsaMessage * message, LibBalsaMessageBody * body,
 
     if (sig_res == GPG_ERR_NO_ERROR) {
         if (body->sig_info->validity >= GPGME_VALIDITY_MARGINAL &&
-            body->sig_info->trust >= GPGME_VALIDITY_MARGINAL)
+            body->sig_info->key->owner_trust >= GPGME_VALIDITY_MARGINAL)
             libbalsa_information(LIBBALSA_INFORMATION_DEBUG,
                                  _("Detected a good signature"));
         else
diff --git a/src/main.c b/src/main.c
index 9f00192..e44ddc1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -63,8 +63,8 @@
 #include "libinit_balsa/assistant_init.h"
 
 #ifdef HAVE_GPGME
-#include <string.h>
-#include <gpgme.h>
+#include "libbalsa-gpgme.h"
+#include "libbalsa-gpgme-cb.h"
 #endif
 
 #ifdef BALSA_USE_THREADS
@@ -757,26 +757,6 @@ balsa_progress_set_activity(gboolean set, const gchar * text)
     gdk_threads_leave();
 }
 
-#if defined(ENABLE_NLS) && defined(HAVE_GPGME)
-static const gchar *
-get_utf8_locale(int category)
-{
-    gchar * locale;
-    static gchar localebuf[64];  /* should be large enough */
-    gchar * dot;
-
-    if (!(locale = setlocale(category, NULL)))
-	return NULL;
-    strncpy(localebuf, locale, 57);
-    localebuf[57] = '\0';
-    dot = strchr(localebuf, '.');
-    if (!dot)
-	dot = localebuf + strlen(localebuf);
-    strcpy(dot, ".UTF-8");
-    return localebuf;
-}
-#endif
-
 /* -------------------------- main --------------------------------- */
 int
 main(int argc, char *argv[])
@@ -846,27 +826,9 @@ main(int argc, char *argv[])
 #endif                          /* HAVE_UNIQUE */
 
 #ifdef HAVE_GPGME
-    /* initialise the gpgme library */
-    g_message("init gpgme version %s", gpgme_check_version(NULL));
-#ifdef HAVE_GPG
-    /* configure the GnuPG engine if a specific gpg path has been detected*/
-    gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, GPG_PATH, NULL);
-#endif
-#ifdef ENABLE_NLS
-    gpgme_set_locale(NULL, LC_CTYPE, get_utf8_locale(LC_CTYPE));
-    gpgme_set_locale(NULL, LC_MESSAGES, get_utf8_locale(LC_MESSAGES));
-#endif /* ENABLE_NLS */
-    { /* scope */
-	gpgme_engine_info_t e;
-
-	if (gpgme_get_engine_info(&e) == GPG_ERR_NO_ERROR)
-	    while (e) {
-		g_message("protocol %s: engine %s (home %s, version %s)",
-			  gpgme_get_protocol_name(e->protocol),
-			  e->file_name, e->home_dir, e->version);
-		e = e->next;
-	    }
-    }
+    /* initialise the gpgme library and set the callback funcs */
+    libbalsa_gpgme_init(lb_gpgme_passphrase, lb_gpgme_select_key,
+			lb_gpgme_accept_low_trust_key);
 #endif
 
     balsa_app_init();
@@ -932,13 +894,9 @@ main(int argc, char *argv[])
 
 #ifdef HAVE_GPGME
     balsa_app.has_openpgp =
-        libbalsa_check_crypto_engine(GPGME_PROTOCOL_OpenPGP);
-#ifdef HAVE_SMIME
+        libbalsa_gpgme_check_crypto_engine(GPGME_PROTOCOL_OpenPGP);
     balsa_app.has_smime =
-       libbalsa_check_crypto_engine(GPGME_PROTOCOL_CMS);
-#else
-    balsa_app.has_smime = FALSE;
-#endif /* HAVE_SMIME */
+        libbalsa_gpgme_check_crypto_engine(GPGME_PROTOCOL_CMS);
 #endif /* HAVE_GPGME */
 
     if (opt_compose_email || opt_attach_list) {



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