[Commits] [SCM] claws branch, master, updated. 3.18.0-282-g990d70e41

jonathan at claws-mail.org jonathan at claws-mail.org
Thu Nov 4 23:24:27 UTC 2021


The branch, master has been updated
       via  990d70e414052e42922c439e9da4d574c4d0cb6a (commit)
       via  ee26f858ed631c05253a1ecb6e10ffd76198fc5e (commit)
       via  932dfa4eb56fe96b0c82eed31cebc6a7b17dea7f (commit)
       via  ca14c79c3a27ae0ad22508ff815d20617773d476 (commit)
       via  24c45b9e1be985888995ed7544c86bf3bc882b6d (commit)
       via  b00919ab9ecaa29daeccd3632709f07f5e702391 (commit)
       via  b52781b8c44a3796d6f5c0b8d33a386938cf6164 (commit)
       via  6596986bb6f093716c38f9af25f5771a88b6747a (commit)
       via  2608cac9b36213f5a519f2ed810b3210be0c03b9 (commit)
      from  621550bd6414994882bfe3dafd314556f911aac6 (commit)

Summary of changes:
 configure.ac                                   |   2 +-
 src/addrduplicates.c                           |   2 +-
 src/common/utils.c                             |  68 ----
 src/common/utils.h                             |  14 -
 src/compose.c                                  |  22 +-
 src/compose.h                                  |   2 +-
 src/main.c                                     |  10 -
 src/mimeview.c                                 | 394 +++++++-----------
 src/mimeview.h                                 |  28 +-
 src/plugins/notification/notification_plugin.c |   8 -
 src/plugins/pgpcore/claws.def                  |   3 +
 src/plugins/pgpcore/pgp_viewer.c               |   1 +
 src/plugins/pgpcore/plugin.def                 |  42 +-
 src/plugins/pgpcore/sgpgme.c                   | 200 ++++++++-
 src/plugins/pgpcore/sgpgme.h                   |  30 +-
 src/plugins/pgpinline/claws.def                |   2 +
 src/plugins/pgpinline/pgpinline.c              | 324 +++++++++------
 src/plugins/pgpinline/plugin.c                 |   2 +-
 src/plugins/pgpmime/claws.def                  |   7 +-
 src/plugins/pgpmime/mypgpcore.def              |   7 +-
 src/plugins/pgpmime/pgpmime.c                  | 218 +++-------
 src/plugins/pgpmime/plugin.c                   |   4 +-
 src/plugins/smime/claws.def                    |   9 +-
 src/plugins/smime/mypgpcore.def                |   5 +-
 src/plugins/smime/plugin.c                     |  10 +-
 src/plugins/smime/smime.c                      | 542 ++++++++++++++++---------
 src/prefs_account.c                            |  34 +-
 src/privacy.c                                  | 117 +++---
 src/privacy.h                                  |  36 +-
 src/procmime.c                                 |   5 +-
 src/procmime.h                                 |   7 +-
 src/procmsg.c                                  |   8 +-
 32 files changed, 1177 insertions(+), 986 deletions(-)


- Log -----------------------------------------------------------------
commit 990d70e414052e42922c439e9da4d574c4d0cb6a
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Sun Oct 31 20:26:38 2021 -0700

    Use global IO timeout value for signature check

diff --git a/src/mimeview.c b/src/mimeview.c
index 9cd41fc55..451e8c169 100644
--- a/src/mimeview.c
+++ b/src/mimeview.c
@@ -1238,7 +1238,8 @@ static void check_signature_cb(GtkWidget *widget, gpointer user_data)
 		check_signature_async_cb,
 		mimeview);
 	if (ret == 0) {
-		mimeview->sig_check_timeout_tag = g_timeout_add_seconds(5, mimeview_check_sig_timeout, mimeview);
+		mimeview->sig_check_timeout_tag = g_timeout_add_seconds(prefs_common.io_timeout_secs,
+			mimeview_check_sig_timeout, mimeview);
 	} else if (ret < 0) {
 		g_object_unref(mimeview->sig_check_cancellable);
 		mimeview->sig_check_cancellable = NULL;

commit ee26f858ed631c05253a1ecb6e10ffd76198fc5e
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Fri Oct 29 10:27:13 2021 -0700

    Fix build error with -Werror=format-security

diff --git a/src/plugins/pgpcore/sgpgme.c b/src/plugins/pgpcore/sgpgme.c
index b4281069e..3d804210d 100644
--- a/src/plugins/pgpcore/sgpgme.c
+++ b/src/plugins/pgpcore/sgpgme.c
@@ -94,7 +94,7 @@ void cm_check_detached_sig(GTask *task,
 	gboolean return_err = TRUE;
 	gboolean cancelled = FALSE;
 	SigCheckTaskResult *task_result = NULL;
-	char err_str[GPGERR_BUFSIZE];
+	char err_str[GPGERR_BUFSIZE] = "";
 
 	domain = g_quark_from_static_string("claws_pgpcore");
 
@@ -202,7 +202,7 @@ out:
 		return;
 
 	if (return_err)
-		g_task_return_new_error(task, domain, err, err_str);
+		g_task_return_new_error(task, domain, err, "%s", err_str);
 	else
 		g_task_return_pointer(task, task_result, privacy_free_sig_check_task_result);
 }
diff --git a/src/plugins/pgpinline/pgpinline.c b/src/plugins/pgpinline/pgpinline.c
index 8faad1d8c..5bd38775f 100644
--- a/src/plugins/pgpinline/pgpinline.c
+++ b/src/plugins/pgpinline/pgpinline.c
@@ -178,7 +178,7 @@ static void pgpinline_check_sig_task(GTask *task,
 	gboolean cancelled = FALSE;
 	SigCheckTaskResult *task_result = NULL;
 	gchar *textstr;
-	char err_str[GPGERR_BUFSIZE];
+	char err_str[GPGERR_BUFSIZE] = "";
 
 	domain = g_quark_from_static_string("claws_pgpinline");
 
@@ -262,7 +262,7 @@ out:
 		return;
 
 	if (return_err)
-		g_task_return_new_error(task, domain, err, err_str);
+		g_task_return_new_error(task, domain, err, "%s", err_str);
 	else
 		g_task_return_pointer(task, task_result, privacy_free_sig_check_task_result);
 }
diff --git a/src/plugins/smime/smime.c b/src/plugins/smime/smime.c
index 5f8899e7e..e920936ae 100644
--- a/src/plugins/smime/smime.c
+++ b/src/plugins/smime/smime.c
@@ -235,7 +235,7 @@ static void check_pkcs7_mime_sig_task(GTask *task,
 	MimeInfo *created = NULL;
 	GString *verified;
 	gchar *tmp;
-	char err_str[GPGERR_BUFSIZE];
+	char err_str[GPGERR_BUFSIZE] = "";
 
 	domain = g_quark_from_static_string("claws_smime");
 
@@ -350,7 +350,7 @@ out:
 		return;
 
 	if (return_err)
-		g_task_return_new_error(task, domain, err, err_str);
+		g_task_return_new_error(task, domain, err, "%s", err_str);
 	else
 		g_task_return_pointer(task, task_result, privacy_free_sig_check_task_result);
 }

commit 932dfa4eb56fe96b0c82eed31cebc6a7b17dea7f
Author: Michael Rasmussen <mir at datanom.net>
Date:   Fri Oct 29 19:08:59 2021 +0200

    Fix CID 1493278
    
    Signed-off-by: Michael Rasmussen <mir at datanom.net>

diff --git a/src/plugins/smime/smime.c b/src/plugins/smime/smime.c
index 477f74c2a..5f8899e7e 100644
--- a/src/plugins/smime/smime.c
+++ b/src/plugins/smime/smime.c
@@ -443,7 +443,6 @@ static gint check_pkcs7_mime_sig(MimeInfo *mimeinfo,
 	mimeinfo->last_sig_check_task = NULL;
 
 	task_result = g_task_propagate_pointer(task, &error);
-	g_object_unref(task);
 	if (unref_cancellable)
 		g_object_unref(cancellable);
 
@@ -455,9 +454,11 @@ static gint check_pkcs7_mime_sig(MimeInfo *mimeinfo,
 	if (task_result == NULL) {
 		debug_print("sig check task propagated NULL task:%p GError: domain:%s code:%d message:\"%s\"\n",
 			task, g_quark_to_string(error->domain), error->code, error->message);
+                g_object_unref(task);
 		g_error_free(error);
 		return -1;
 	}
+	g_object_unref(task);
 
 	mimeinfo->sig_data = task_result->sig_data;
 

commit ca14c79c3a27ae0ad22508ff815d20617773d476
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Fri Oct 29 08:56:44 2021 -0700

    Check for null pointer

diff --git a/src/plugins/pgpinline/pgpinline.c b/src/plugins/pgpinline/pgpinline.c
index 37321be9e..8faad1d8c 100644
--- a/src/plugins/pgpinline/pgpinline.c
+++ b/src/plugins/pgpinline/pgpinline.c
@@ -412,7 +412,8 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	
 	if (plain == NULL) {
 		g_free(textdata);
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -422,7 +423,8 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	if ((dstfp = claws_fopen(fname, "wb")) == NULL) {
 		FILE_OP_ERROR(fname, "claws_fopen");
 		privacy_set_error(_("Couldn't open decrypted file %s"), fname);
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		g_free(textdata);
 		g_free(fname);
 		gpgme_data_release(plain);
@@ -497,7 +499,8 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 		privacy_set_error(_("Couldn't close decrypted file %s"), fname);
         	g_free(fname);
         	gpgme_data_release(plain);
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	
@@ -506,7 +509,8 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	
 	if (parseinfo == NULL) {
 		privacy_set_error(_("Couldn't scan decrypted file."));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	decinfo = g_node_first_child(parseinfo->node) != NULL ?
@@ -514,7 +518,8 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 		
 	if (decinfo == NULL) {
 		privacy_set_error(_("Couldn't scan decrypted file parts."));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -540,7 +545,8 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	return decinfo;
 
 FILE_ERROR:
-	privacy_free_signature_data(sig_data);
+	if (sig_data)
+		privacy_free_signature_data(sig_data);
 	g_free(textdata);
 	claws_fclose(dstfp);
 	g_free(fname);
diff --git a/src/plugins/pgpmime/pgpmime.c b/src/plugins/pgpmime/pgpmime.c
index 5f0ca0b96..a3e1142e6 100644
--- a/src/plugins/pgpmime/pgpmime.c
+++ b/src/plugins/pgpmime/pgpmime.c
@@ -249,7 +249,8 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	gpgme_data_release(cipher);
 	if (plain == NULL) {
 		debug_print("plain is null!\n");
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -259,7 +260,8 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	if ((dstfp = claws_fopen(fname, "wb")) == NULL) {
 		FILE_OP_ERROR(fname, "claws_fopen");
 		privacy_set_error(_("Couldn't open decrypted file %s"), fname);
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		g_free(fname);
 		gpgme_data_release(plain);
 		debug_print("can't open!\n");
@@ -270,7 +272,8 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 		FILE_OP_ERROR(fname, "fprintf");
 		claws_fclose(dstfp);
 		privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		g_free(fname);
 		gpgme_data_release(plain);
 		debug_print("can't open!\n");
@@ -284,7 +287,8 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 			g_free(chars);
 			claws_fclose(dstfp);
 			privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
-			privacy_free_signature_data(sig_data);
+			if (sig_data)
+				privacy_free_signature_data(sig_data);
 			g_free(fname);
 			gpgme_data_release(plain);
 			debug_print("can't open!\n");
@@ -296,7 +300,8 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	if (claws_safe_fclose(dstfp) == EOF) {
 		FILE_OP_ERROR(fname, "claws_fclose");
 		privacy_set_error(_("Couldn't close decrypted file %s"), fname);
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		g_free(fname);
 		gpgme_data_release(plain);
 		debug_print("can't open!\n");
@@ -307,14 +312,16 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	g_free(fname);
 	if (parseinfo == NULL) {
 		privacy_set_error(_("Couldn't parse decrypted file."));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	decinfo = g_node_first_child(parseinfo->node) != NULL ?
 		g_node_first_child(parseinfo->node)->data : NULL;
 	if (decinfo == NULL) {
 		privacy_set_error(_("Couldn't parse decrypted file parts."));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
diff --git a/src/plugins/smime/smime.c b/src/plugins/smime/smime.c
index f135714c8..477f74c2a 100644
--- a/src/plugins/smime/smime.c
+++ b/src/plugins/smime/smime.c
@@ -586,7 +586,8 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
 	gpgme_data_release(cipher);
 	if (plain == NULL) {
 		debug_print("plain is null!\n");
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -599,7 +600,8 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         	gpgme_data_release(plain);
 		debug_print("can't open!\n");
 		privacy_set_error(_("Couldn't open temporary file"));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
     	}
 
@@ -610,7 +612,8 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         	gpgme_data_release(plain);
 		debug_print("can't close!\n");
 		privacy_set_error(_("Couldn't write to temporary file"));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -625,7 +628,8 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         		gpgme_data_release(plain);
 			debug_print("can't write!\n");
 			privacy_set_error(_("Couldn't write to temporary file"));
-			privacy_free_signature_data(sig_data);
+			if (sig_data)
+				privacy_free_signature_data(sig_data);
 			return NULL;
 		}
 	}
@@ -636,7 +640,8 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         	gpgme_data_release(plain);
 		debug_print("can't close!\n");
 		privacy_set_error(_("Couldn't close temporary file"));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	g_free(chars);
@@ -645,14 +650,16 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
 	g_free(fname);
 	if (parseinfo == NULL) {
 		privacy_set_error(_("Couldn't parse decrypted file."));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	decinfo = g_node_first_child(parseinfo->node) != NULL ?
 		g_node_first_child(parseinfo->node)->data : NULL;
 	if (decinfo == NULL) {
 		privacy_set_error(_("Couldn't parse decrypted file parts."));
-		privacy_free_signature_data(sig_data);
+		if (sig_data)
+			privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
diff --git a/src/privacy.c b/src/privacy.c
index a77e9a814..0a1d7881c 100644
--- a/src/privacy.c
+++ b/src/privacy.c
@@ -113,6 +113,8 @@ void privacy_free_signature_data(gpointer data)
 {
 	SignatureData *sig_data = (SignatureData *)data;
 
+	cm_return_if_fail(sig_data != NULL);
+
 	g_free(sig_data->info_short);
 	g_free(sig_data->info_full);
 	g_free(sig_data);

commit 24c45b9e1be985888995ed7544c86bf3bc882b6d
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Fri Oct 29 08:47:10 2021 -0700

    set min plugin version for new privacy interface

diff --git a/src/plugins/pgpinline/plugin.c b/src/plugins/pgpinline/plugin.c
index fb5ea816b..239fa6e75 100644
--- a/src/plugins/pgpinline/plugin.c
+++ b/src/plugins/pgpinline/plugin.c
@@ -35,7 +35,7 @@
 
 gint plugin_init(gchar **error)
 {
-	if (!check_plugin_version(MAKE_NUMERIC_VERSION(4,0,0,441),
+	if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,18,0,277),
 				VERSION_NUMERIC, PLUGIN_NAME, error))
   		return -1;
 
diff --git a/src/plugins/pgpmime/plugin.c b/src/plugins/pgpmime/plugin.c
index 3ca210324..dfd435e8b 100644
--- a/src/plugins/pgpmime/plugin.c
+++ b/src/plugins/pgpmime/plugin.c
@@ -35,7 +35,7 @@
 
 gint plugin_init(gchar **error)
 {
-	if (!check_plugin_version(MAKE_NUMERIC_VERSION(4,0,0,441),
+	if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,18,0,277),
 				VERSION_NUMERIC, PLUGIN_NAME, error))
 		return -1;
 
diff --git a/src/plugins/smime/plugin.c b/src/plugins/smime/plugin.c
index 05c1db38e..579ea513e 100644
--- a/src/plugins/smime/plugin.c
+++ b/src/plugins/smime/plugin.c
@@ -36,7 +36,7 @@
 
 gint plugin_init(gchar **error)
 {
-	if (!check_plugin_version(MAKE_NUMERIC_VERSION(4,0,0,441),
+	if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,18,0,277),
 				VERSION_NUMERIC, PLUGIN_NAME, error))
 		return -1;
 

commit b00919ab9ecaa29daeccd3632709f07f5e702391
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Mon Aug 2 23:02:40 2021 -0700

    fix bug 4517, 'Thread safety issues in signature checking code'
    
    Move from using raw pthreads to GLib tasks for safety and convenience.
    Also includes some extra fixes for leaked gpgme keys and contexts.

diff --git a/src/mimeview.c b/src/mimeview.c
index 24b89495f..9cd41fc55 100644
--- a/src/mimeview.c
+++ b/src/mimeview.c
@@ -549,26 +549,11 @@ void mimeview_show_message(MimeView *mimeview, MimeInfo *mimeinfo,
 					  mimeview_selected, mimeview);
 }
 
-#ifdef USE_PTHREAD
-static void mimeview_check_sig_cancel_now(MimeView *mimeview);
-#endif
-
 static void mimeview_free_mimeinfo(MimeView *mimeview)
 {
-	gboolean defer = FALSE;
-#ifdef USE_PTHREAD
-	defer = (mimeview->check_data != NULL);
-	if (defer)
-		mimeview->check_data->free_after_use = TRUE;
-#endif
-	if (mimeview->mimeinfo != NULL && !defer) {
+	if (mimeview->mimeinfo != NULL) {
 		procmime_mimeinfo_free_all(&mimeview->mimeinfo);
 		mimeview->mimeinfo = NULL;
-	} else if (defer) {
-#ifdef USE_PTHREAD
-		debug_print("deferring free(mimeinfo) and cancelling check\n");
-		mimeview_check_sig_cancel_now(mimeview);
-#endif
 	}
 }
 
@@ -583,20 +568,19 @@ void mimeview_destroy(MimeView *mimeview)
 	g_slist_free(mimeview->viewers);
 	gtk_target_list_unref(mimeview->target_list);
 
-#ifdef USE_PTHREAD
-	if (mimeview->check_data) {
-		mimeview->check_data->destroy_mimeview = TRUE;
-		debug_print("deferring destroy\n");
-	} else 
-#endif
-	{
-		mimeview_free_mimeinfo(mimeview);
-		gtk_tree_path_free(mimeview->opened);
-		g_free(mimeview->file);
-		g_free(mimeview);
-		mimeviews = g_slist_remove(mimeviews, mimeview);
+	if (mimeview->sig_check_timeout_tag != 0)
+		g_source_remove(mimeview->sig_check_timeout_tag);
+	if (mimeview->sig_check_cancellable != NULL) {
+		/* Set last_sig_check_task to NULL to discard results in async_cb */
+		mimeview->siginfo->last_sig_check_task = NULL;
+		g_cancellable_cancel(mimeview->sig_check_cancellable);
+		g_object_unref(mimeview->sig_check_cancellable);
 	}
-	
+	mimeview_free_mimeinfo(mimeview);
+	gtk_tree_path_free(mimeview->opened);
+	g_free(mimeview->file);
+	g_free(mimeview);
+	mimeviews = g_slist_remove(mimeviews, mimeview);
 }
 
 MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
@@ -990,6 +974,19 @@ void mimeview_clear(MimeView *mimeview)
 	if (g_slist_find(mimeviews, mimeview) == NULL)
 		return;
 	
+	if (mimeview->sig_check_timeout_tag != 0) {
+		g_source_remove(mimeview->sig_check_timeout_tag);
+		mimeview->sig_check_timeout_tag = 0;
+	}
+
+	if (mimeview->sig_check_cancellable != NULL) {
+		/* Set last_sig_check_task to NULL to discard results in async_cb */
+		mimeview->siginfo->last_sig_check_task = NULL;
+		g_cancellable_cancel(mimeview->sig_check_cancellable);
+		g_object_unref(mimeview->sig_check_cancellable);
+		mimeview->sig_check_cancellable = NULL;
+	}
+
 	noticeview_hide(mimeview->siginfoview);
 
 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mimeview->ctree));
@@ -1027,21 +1024,20 @@ gchar * get_message_check_signature_shortcut(MessageView *messageview) {
 static void check_signature_cb(GtkWidget *widget, gpointer user_data);
 static void display_full_info_cb(GtkWidget *widget, gpointer user_data);
 
-static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo, 
-					gboolean special, SignatureStatus code)
+static void update_signature_noticeview(MimeView *mimeview, gboolean special, SignatureStatus code)
 {
 	gchar *text = NULL, *button_text = NULL;
 	void  *func = NULL;
 	StockPixmap icon = STOCK_PIXMAP_PRIVACY_SIGNED;
 	SignatureStatus mycode = SIGNATURE_UNCHECKED;
 	
-	cm_return_if_fail(mimeview != NULL);
-	cm_return_if_fail(mimeinfo != NULL);
-	
+	if (mimeview == NULL || mimeview->siginfo == NULL)
+		g_error("bad call to update noticeview");
+
 	if (special)
 		mycode = code;
-	else 
-		mycode = privacy_mimeinfo_get_sig_status(mimeinfo);
+	else
+		mycode = privacy_mimeinfo_get_sig_status(mimeview->siginfo);
 
 	switch (mycode) {
 	case SIGNATURE_UNCHECKED:
@@ -1069,6 +1065,7 @@ static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo,
 		func = display_full_info_cb;
 		icon = STOCK_PIXMAP_PRIVACY_FAILED;
 		break;
+	case SIGNATURE_CHECK_ERROR:
 	case SIGNATURE_CHECK_FAILED:
 	case SIGNATURE_CHECK_TIMEOUT:
 		button_text = _("Check again");
@@ -1078,19 +1075,17 @@ static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo,
 	default:
 		break;
 	}
+
 	if (mycode == SIGNATURE_UNCHECKED) {
-		gchar *tmp = privacy_mimeinfo_sig_info_short(mimeinfo);
+		gchar *tmp = privacy_mimeinfo_get_sig_info(mimeview->siginfo, FALSE);
 		gchar *shortcut = get_message_check_signature_shortcut(mimeview->messageview);
 
 		if (*shortcut == '\0')
 			text = g_strdup_printf(_("%s Click the icon to check it."), tmp);
 		else
-			text = g_strdup_printf(_("%s Click the icon or hit '%s' to check it."),
-				tmp, shortcut);
-		g_free(tmp);
+			text = g_strdup_printf(_("%s Click the icon or hit '%s' to check it."), tmp, shortcut);
+
 		g_free(shortcut);
-	} else if (mycode != SIGNATURE_CHECK_TIMEOUT) {
-		text = privacy_mimeinfo_sig_info_short(mimeinfo);
 	} else if (mycode == SIGNATURE_CHECK_TIMEOUT) {
 		gchar *shortcut = get_message_check_signature_shortcut(mimeview->messageview);
 
@@ -1098,13 +1093,25 @@ static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo,
 			text = g_strdup(_("Timeout checking the signature. Click the icon to try again."));
 		else
 			text = g_strdup_printf(_("Timeout checking the signature. Click the icon or hit '%s' to try again."), shortcut);
+
+		g_free(shortcut);
+	} else if (mycode == SIGNATURE_CHECK_ERROR) {
+		gchar *shortcut = get_message_check_signature_shortcut(mimeview->messageview);
+
+		if (*shortcut == '\0')
+			text = g_strdup(_("Error checking the signature. Click the icon to try again."));
+		else
+			text = g_strdup_printf(_("Error checking the signature. Click the icon or hit '%s' to try again."), shortcut);
+
 		g_free(shortcut);
+	} else {
+		text = g_strdup(privacy_mimeinfo_get_sig_info(mimeview->siginfo, FALSE));
 	}
 
 	noticeview_set_text(mimeview->siginfoview, text);
 	gtk_label_set_selectable(GTK_LABEL(mimeview->siginfoview->text), TRUE);
-
 	g_free(text);
+
 	noticeview_set_button_text(mimeview->siginfoview, NULL);
 	noticeview_set_button_press_callback(
 		mimeview->siginfoview,
@@ -1117,242 +1124,129 @@ static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo,
 	icon_list_create(mimeview, mimeview->mimeinfo);
 }
 
-#ifdef USE_PTHREAD
-
-/* reset all thread stuff, and do the cleanups we've been left to do */
-static void mimeview_check_data_reset(MimeView *mimeview)
+static void check_signature_async_cb(GObject *source_object,
+	GAsyncResult *async_result,
+	gpointer user_data)
 {
-	gboolean must_free;
-	gboolean must_destroy;
+	GTask *task = G_TASK(async_result);
+	GCancellable *cancellable;
+	MimeView *mimeview = (MimeView *)user_data;
+	gboolean cancelled;
+	SigCheckTaskResult *result;
+	GError *error = NULL;
 
-	if (!mimeview->check_data)
+	if (mimeview->siginfo == NULL) {
+		debug_print("discarding stale sig check task result task:%p\n", task);
 		return;
-
-	must_free = mimeview->check_data->free_after_use;
-	must_destroy = mimeview->check_data->destroy_mimeview;
-	
-	if (mimeview->check_data->cancel_th_init) {
-		debug_print("killing canceller thread\n");
-		mimeview->check_data->cancel_th_init = FALSE;
-		pthread_cancel(mimeview->check_data->cancel_th);
-	}
-
-	if (must_free) {
-		debug_print("freeing deferred mimeinfo\n");
-		procmime_mimeinfo_free_all(&mimeview->check_data->siginfo);
+	} else if (task != mimeview->siginfo->last_sig_check_task) {
+		debug_print("discarding stale sig check task result last_task:%p task:%p\n",
+			mimeview->siginfo->last_sig_check_task, task);
+		return;
+	} else {
+		debug_print("using sig check task result task:%p\n", task);
+		mimeview->siginfo->last_sig_check_task = NULL;
 	}
 
-	g_free(mimeview->check_data);
-	mimeview->check_data = NULL;
+	cancellable = g_task_get_cancellable(task);
+	cancelled = g_cancellable_set_error_if_cancelled(cancellable, &error);
+	if (cancelled) {
+		debug_print("sig check task was cancelled: task:%p GError: domain:%s code:%d message:\"%s\"\n",
+			task, g_quark_to_string(error->domain), error->code, error->message);
+		g_error_free(error);
+		update_signature_noticeview(mimeview, TRUE, SIGNATURE_CHECK_TIMEOUT);
+		return;
+	} else {
+		if (mimeview->sig_check_cancellable == NULL)
+			g_error("bad cancellable");
+		if (mimeview->sig_check_timeout_tag == 0)
+			g_error("bad cancel source tag");
 
-	if (must_destroy) {
-		debug_print("freeing deferred mimeview\n");
-		mimeview_free_mimeinfo(mimeview);
-		gtk_tree_path_free(mimeview->opened);
-		g_free(mimeview->file);
-		g_free(mimeview);
-		mimeviews = g_slist_remove(mimeviews, mimeview);
+		g_source_remove(mimeview->sig_check_timeout_tag);
+		mimeview->sig_check_timeout_tag = 0;
+		g_object_unref(mimeview->sig_check_cancellable);
+		mimeview->sig_check_cancellable = NULL;
 	}
-}
 
-/* GUI update once the checker thread is done or killed */
-static gboolean mimeview_check_sig_thread_cb(void *data)
-{
-	MimeView *mimeview = (MimeView *) data;
-	MimeInfo *mimeinfo = mimeview->siginfo;
+	result = g_task_propagate_pointer(task, &error);
 
-	debug_print("mimeview_check_sig_thread_cb\n");
-	
-	if (mimeinfo == NULL) {
-		/* message changed !? */
-		g_warning("no more siginfo!");
-		goto end;
-	}
-	
-	if (!mimeview->check_data) {
-		g_warning("nothing to check");
-		return FALSE;
+	if (mimeview->siginfo->sig_data) {
+		privacy_free_signature_data(mimeview->siginfo->sig_data);
+		mimeview->siginfo->sig_data = NULL;
 	}
 
-	if (mimeview->check_data->siginfo != mimeinfo) {
-		/* message changed !? */
-		g_warning("different siginfo!");
-		goto end;
-	}
-
-	if (mimeview->check_data->destroy_mimeview ||
-	    mimeview->check_data->free_after_use) {
-	    	debug_print("not bothering, we're changing message\n"); 
-		goto end;
+	if (result == NULL) {
+		debug_print("sig check task propagated NULL task:%p GError: domain:%s code:%d message:\"%s\"\n",
+			task, g_quark_to_string(error->domain), error->code, error->message);
+		g_error_free(error);
+		update_signature_noticeview(mimeview, TRUE, SIGNATURE_CHECK_ERROR);
+		return;
 	}
-	
-	/* update status */
-	if (mimeview->check_data->timeout) 
-		update_signature_noticeview(mimeview, mimeview->siginfo, 
-			TRUE, SIGNATURE_CHECK_TIMEOUT);
-	else
-		update_signature_noticeview(mimeview, mimeview->siginfo, 
-			FALSE, 0);
 
-end:
-	mimeview_check_data_reset(mimeview);
-	return FALSE;
-}
+	mimeview->siginfo->sig_data = result->sig_data;
+	update_signature_noticeview(mimeview, FALSE, 0);
 
-/* sig checker thread */
-static void *mimeview_check_sig_worker_thread(void *data)
-{
-	MimeView *mimeview = (MimeView *)data;
-	MimeInfo *mimeinfo = mimeview->siginfo;
-	
-	debug_print("checking...\n");
-
-	if (!mimeview->check_data)
-		return NULL;
-
-	if (mimeinfo && mimeinfo == mimeview->check_data->siginfo) {
-		privacy_mimeinfo_check_signature(mimeinfo);
-		if (mimeview->check_data && mimeview->check_data->cancel_th_init) {
-			mimeview->check_data->cancel_th_init = FALSE;
-			pthread_cancel(mimeview->check_data->cancel_th);
-		}
-	} else {
-		/* that's strange! we changed message without 
-		 * getting killed. */
-		g_warning("different siginfo!");
-		mimeview_check_data_reset(mimeview);
-		return NULL;
+	if (result->newinfo) {
+		g_warning("Check sig task returned an unexpected new MimeInfo");
+		procmime_mimeinfo_free_all(&result->newinfo);
 	}
 
-	/* use g_timeout so that GUI updates is done from the
-	 * correct thread */
-	g_timeout_add(0,mimeview_check_sig_thread_cb,mimeview);
-	
-	return NULL;
+	g_free(result);
 }
 
-/* killer thread - acts when the checker didn't work fast
- * enough. */
-static void *mimeview_check_sig_cancel_thread(void *data)
+gboolean mimeview_check_sig_timeout(gpointer user_data)
 {
-	MimeView *mimeview = (MimeView *)data;
-	
-	if (!mimeview->check_data)
-		return NULL; /* nothing to kill ! */
+	MimeView *mimeview = (MimeView *)user_data;
+	GCancellable *cancellable = mimeview->sig_check_cancellable;
 
-	/* wait for a few seconds... */
-	debug_print("waiting a while\n");
+	mimeview->sig_check_timeout_tag = 0;
 
-	g_usleep(5 * 1000 * 1000);
-	
-	if (!mimeview->check_data)
-		return NULL; /* nothing to kill, it's done in time :) */
-	
-	/* too late, go away checker thread */
-	debug_print("killing checker thread\n");
-	if (mimeview->check_data->th_init) {
-		mimeview->check_data->th_init = FALSE;
-		pthread_cancel(mimeview->check_data->th);
+	if (cancellable == NULL) {
+		return G_SOURCE_REMOVE;
 	}
 
-	/* tell upstream it was a timeout */
-	mimeview->check_data->timeout = TRUE;
-	/* use g_timeout so that GUI updates is done from the
-	 * correct thread */
-	g_timeout_add(0,mimeview_check_sig_thread_cb,mimeview);
+	mimeview->sig_check_cancellable = NULL;
+	g_cancellable_cancel(cancellable);
+	g_object_unref(cancellable);
 
-	return NULL;
+	return G_SOURCE_REMOVE;
 }
 
-/* get rid of the checker thread right now - used when changing the
- * displayed message for example. */
-static void mimeview_check_sig_cancel_now(MimeView *mimeview)
-{
-	if (!mimeview->check_data)
-		return;
-	debug_print("killing checker thread NOW\n");
-	if (mimeview->check_data->th_init) {
-		mimeview->check_data->th_init = FALSE;
-		pthread_cancel(mimeview->check_data->th);
-	}
-
-	/* tell upstream it was a timeout */
-	mimeview->check_data->timeout = TRUE;
-	mimeview_check_sig_thread_cb(mimeview);
-	return;
-}
-
-/* creates a thread to check the signature, and a second one
- * to kill the first one after a timeout */
-static void mimeview_check_sig_in_thread(MimeView *mimeview)
-{
-	pthread_t th, th2;
-	pthread_attr_t detach, detach2;
-	
-	if (mimeview->check_data) {
-		g_warning("already checking it");
-		return;
-	}
-	
-	mimeview->check_data = g_new0(SigCheckData, 1);
-	mimeview->check_data->siginfo = mimeview->siginfo;
-	debug_print("creating thread\n");
-
-	/* init thread attributes and create the checker thread */
-	if (pthread_attr_init(&detach) != 0 ||
-	    pthread_attr_setdetachstate(&detach, PTHREAD_CREATE_DETACHED) != 0 ||
-	    pthread_attr_init(&detach2) != 0 ||
-	    pthread_attr_setdetachstate(&detach2, PTHREAD_CREATE_DETACHED) != 0 ||
-	    pthread_create(&th, &detach, 
-			mimeview_check_sig_worker_thread, 
-			mimeview) != 0) {
-		/* arh. We'll do it synchronously. */
-		g_warning("can't create checked thread");
-		g_free(mimeview->check_data);
-		mimeview->check_data = NULL;
-		return;
-	} else {
-		mimeview->check_data->th = th;
-		mimeview->check_data->th_init = TRUE;
-	}
-
-	/* create the killer thread */
-	if (pthread_create(&th2, &detach2, 
-			mimeview_check_sig_cancel_thread, 
-			mimeview) != 0) {
-		g_warning("can't create killer thread");
-		g_free(mimeview->check_data);
-		mimeview->check_data = NULL;
-		return;
-	} else {
-		mimeview->check_data->cancel_th = th2;
-		mimeview->check_data->cancel_th_init = TRUE;
-	}
-}
-#endif
-
 static void check_signature_cb(GtkWidget *widget, gpointer user_data)
 {
 	MimeView *mimeview = (MimeView *) user_data;
 	MimeInfo *mimeinfo = mimeview->siginfo;
+	gint ret;
 	
 	if (mimeinfo == NULL || !noticeview_is_visible(mimeview->siginfoview))
 		return;
-#ifdef USE_PTHREAD
-	if (mimeview->check_data)
-		return;
-#endif
+
 	noticeview_set_text(mimeview->siginfoview, _("Checking signature..."));
 	GTK_EVENTS_FLUSH();
-#ifdef USE_PTHREAD
-	/* let's do it non-blocking */
-	mimeview_check_sig_in_thread(mimeview);
-	if (!mimeview->check_data) /* let's check syncronously */
-#endif
-	{
-		debug_print("checking without thread\n");
-		privacy_mimeinfo_check_signature(mimeinfo);
-		update_signature_noticeview(mimeview, mimeview->siginfo, FALSE, 0);
+
+	if (mimeview->sig_check_cancellable != NULL) {
+		if (mimeview->sig_check_timeout_tag == 0)
+			g_error("bad cancel source tag");
+		g_source_remove(mimeview->sig_check_timeout_tag);
+		g_cancellable_cancel(mimeview->sig_check_cancellable);
+		g_object_unref(mimeview->sig_check_cancellable);
+	}
+
+	mimeview->sig_check_cancellable = g_cancellable_new();
+
+	ret = privacy_mimeinfo_check_signature(mimeview->siginfo,
+		mimeview->sig_check_cancellable,
+		check_signature_async_cb,
+		mimeview);
+	if (ret == 0) {
+		mimeview->sig_check_timeout_tag = g_timeout_add_seconds(5, mimeview_check_sig_timeout, mimeview);
+	} else if (ret < 0) {
+		g_object_unref(mimeview->sig_check_cancellable);
+		mimeview->sig_check_cancellable = NULL;
+		update_signature_noticeview(mimeview, TRUE, SIGNATURE_CHECK_ERROR);
+	} else {
+		g_object_unref(mimeview->sig_check_cancellable);
+		mimeview->sig_check_cancellable = NULL;
+		update_signature_noticeview(mimeview, FALSE, 0);
 	}
 }
 
@@ -1373,11 +1267,8 @@ static void redisplay_email(GtkWidget *widget, gpointer user_data)
 static void display_full_info_cb(GtkWidget *widget, gpointer user_data)
 {
 	MimeView *mimeview = (MimeView *) user_data;
-	gchar *siginfo;
 
-	siginfo = privacy_mimeinfo_sig_info_full(mimeview->siginfo);
-	textview_set_text(mimeview->textview, siginfo);
-	g_free(siginfo);
+	textview_set_text(mimeview->textview, privacy_mimeinfo_get_sig_info(mimeview->siginfo, TRUE));
 	noticeview_set_button_text(mimeview->siginfoview, NULL);
 	noticeview_set_button_press_callback(
 		mimeview->siginfoview,
@@ -1426,7 +1317,7 @@ static void update_signature_info(MimeView *mimeview, MimeInfo *selected)
 		return;
 	}
 	
-	update_signature_noticeview(mimeview, siginfo, FALSE, 0);
+	update_signature_noticeview(mimeview, FALSE, 0);
 	noticeview_show(mimeview->siginfoview);
 }
 
@@ -2615,6 +2506,7 @@ static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo)
 	if (siginfo != NULL) {
 		switch (privacy_mimeinfo_get_sig_status(siginfo)) {
 		case SIGNATURE_UNCHECKED:
+		case SIGNATURE_CHECK_ERROR:
 		case SIGNATURE_CHECK_FAILED:
 		case SIGNATURE_CHECK_TIMEOUT:
 			pixmap = stock_pixmap_widget_with_overlay(stockp,
@@ -2634,7 +2526,7 @@ static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo)
 			    STOCK_PIXMAP_PRIVACY_EMBLEM_FAILED, OVERLAY_BOTTOM_RIGHT, 6, 3);
 			break;
 		}
-		sigshort = privacy_mimeinfo_sig_info_short(siginfo);
+		sigshort = privacy_mimeinfo_get_sig_info(siginfo, FALSE);
 	} else if (encrypted != NULL) {
 			pixmap = stock_pixmap_widget_with_overlay(stockp,
 			    STOCK_PIXMAP_PRIVACY_EMBLEM_ENCRYPTED, OVERLAY_BOTTOM_RIGHT, 6, 3);		
@@ -2684,7 +2576,6 @@ static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo)
 		g_free(sigshort_escaped);
 		tip = tiptmp;
 	}
-	g_free(sigshort);
 
 	gtk_widget_set_tooltip_markup(button, tip);
 	g_free(tip);
diff --git a/src/mimeview.h b/src/mimeview.h
index 2f87b8c3a..a804cedd3 100644
--- a/src/mimeview.h
+++ b/src/mimeview.h
@@ -1,6 +1,6 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
  *
  * 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
@@ -26,9 +26,6 @@ typedef struct _MimeViewer 		MimeViewer;
 #include <glib.h>
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
-#ifdef USE_PTHREAD
-#include <pthread.h>
-#endif
 
 #include "textview.h"
 #include "messageview.h"
@@ -41,22 +38,6 @@ typedef enum
 	MIMEVIEW_VIEWER
 } MimeViewType;
 
-#ifdef USE_PTHREAD
-typedef struct _SigCheckData SigCheckData;
-struct _SigCheckData
-{
-	pthread_t th;
-	pthread_t cancel_th;
-	gboolean th_init;
-	gboolean cancel_th_init;
-
-	MimeInfo *siginfo;
-	gboolean free_after_use;
-	gboolean destroy_mimeview;
-	gboolean timeout;
-};
-#endif
-
 struct _MimeView
 {
 	GtkWidget *hbox;
@@ -100,9 +81,8 @@ struct _MimeView
 	GtkActionGroup *action_group;
 	gboolean signed_part;
 
-#ifdef USE_PTHREAD
-	SigCheckData *check_data;
-#endif
+	GCancellable *sig_check_cancellable;
+	guint sig_check_timeout_tag;
 };
 
 struct _MimeViewerFactory
diff --git a/src/plugins/pgpcore/claws.def b/src/plugins/pgpcore/claws.def
index 87a931d4c..2ded33e41 100644
--- a/src/plugins/pgpcore/claws.def
+++ b/src/plugins/pgpcore/claws.def
@@ -60,9 +60,12 @@ prefs_set_block_label
 prefs_set_default
 prefs_write_open
 prefs_write_param
+privacy_free_sig_check_task_result
+privacy_free_signature_data
 privacy_get_error
 privacy_set_error
 procmime_mimeinfo_get_parameter
+procmime_mimeinfo_parent
 procmime_decode_content
 procmime_get_tmp_file_name
 procmime_get_part
diff --git a/src/plugins/pgpcore/pgp_viewer.c b/src/plugins/pgpcore/pgp_viewer.c
index b020b75a5..d39b96a09 100644
--- a/src/plugins/pgpcore/pgp_viewer.c
+++ b/src/plugins/pgpcore/pgp_viewer.c
@@ -304,6 +304,7 @@ static void pgpview_show_mime_part(TextView *textview, MimeInfo *partinfo)
 
 		TEXTVIEW_INSERT(":\n\n");
 		TEXTVIEW_INSERT(_("   This key is in your keyring.\n"));
+		gpgme_key_unref(key);
 	}
 	gpgme_data_release(sigdata);
 	gpgme_release(ctx);
diff --git a/src/plugins/pgpcore/plugin.def b/src/plugins/pgpcore/plugin.def
index 1f156d953..c9803ee18 100644
--- a/src/plugins/pgpcore/plugin.def
+++ b/src/plugins/pgpcore/plugin.def
@@ -1,29 +1,29 @@
 EXPORTS
-        plugin_desc
-        plugin_done
-        plugin_init
-        plugin_licence
-        plugin_name
+	plugin_desc
+	plugin_done
+	plugin_init
+	plugin_licence
+	plugin_name
 	plugin_provides
-        plugin_type
-        plugin_version
+	plugin_type
+	plugin_version
 
-        sgpgme_data_from_mimeinfo
+	sgpgme_data_from_mimeinfo
 	sgpgme_data_release_and_get_mem
-        sgpgme_decrypt_verify
-        sgpgme_get_encrypt_data
-        sgpgme_setup_signers
-        sgpgme_sigstat_gpgme_to_privacy
-        sgpgme_sigstat_info_full
-        sgpgme_sigstat_info_short
-        sgpgme_verify_signature
+	sgpgme_decrypt_verify
+	sgpgme_get_encrypt_data
+	sgpgme_setup_signers
+	sgpgme_sigstat_gpgme_to_privacy
+	sgpgme_sigstat_info_full
+	sgpgme_sigstat_info_short
+	sgpgme_verify_signature
 
-        gpgmegtk_passphrase_cb
-        prefs_gpg_add_skip_encryption_warning
-        prefs_gpg_enable_agent
-        prefs_gpg_remove_skip_encryption_warning
-        prefs_gpg_should_skip_encryption_warning
-        prefs_gpg_get_config
+	gpgmegtk_passphrase_cb
+	prefs_gpg_add_skip_encryption_warning
+	prefs_gpg_enable_agent
+	prefs_gpg_remove_skip_encryption_warning
+	prefs_gpg_should_skip_encryption_warning
+	prefs_gpg_get_config
 
 	cm_gpgme_data_rewind
 
diff --git a/src/plugins/pgpcore/sgpgme.c b/src/plugins/pgpcore/sgpgme.c
index 150fd9f47..b4281069e 100644
--- a/src/plugins/pgpcore/sgpgme.c
+++ b/src/plugins/pgpcore/sgpgme.c
@@ -67,6 +67,192 @@ static void sgpgme_disable_all(void)
      * gpgme messages */
 }
 
+void cm_free_detached_sig_task_data(gpointer data)
+{
+	DetachedSigTaskData *task_data = (DetachedSigTaskData *)data;
+
+	g_free(task_data->boundary);
+	g_free(task_data->text_filename);
+	g_free(task_data->sig_filename);
+	g_free(task_data);
+}
+
+void cm_check_detached_sig(GTask *task,
+	gpointer source_object,
+	gpointer _task_data,
+	GCancellable *cancellable)
+{
+	DetachedSigTaskData *task_data = (DetachedSigTaskData *)_task_data;
+	GQuark domain;
+	FILE *fp;
+	gpgme_ctx_t ctx;
+	gpgme_error_t err;
+	gpgme_data_t textdata = NULL;
+	gpgme_data_t sigdata = NULL;
+	gpgme_verify_result_t gpgme_res;
+	gchar *textstr;
+	gboolean return_err = TRUE;
+	gboolean cancelled = FALSE;
+	SigCheckTaskResult *task_result = NULL;
+	char err_str[GPGERR_BUFSIZE];
+
+	domain = g_quark_from_static_string("claws_pgpcore");
+
+	err = gpgme_new(&ctx);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("couldn't initialize GPG context: %s", err_str);
+		goto out;
+	}
+
+	err = gpgme_set_protocol(ctx, task_data->protocol);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("couldn't set GPG protocol: %s", err_str);
+		goto out_ctx;
+	}
+
+	fp = claws_fopen(task_data->text_filename, "rb");
+	if (fp == NULL) {
+		err = GPG_ERR_GENERAL;
+		g_snprintf(err_str, GPGERR_BUFSIZE, "claws_fopen failed");
+		goto out_ctx;
+	}
+
+	textstr = task_data->get_canonical_content(fp, task_data->boundary);
+	claws_fclose(fp);
+
+	err = gpgme_data_new_from_mem(&textdata, textstr, textstr?strlen(textstr):0, 0);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_data_new_from_mem failed: %s", err_str);
+		goto out_textstr;
+	}
+
+	fp = claws_fopen(task_data->sig_filename, "rb");
+	if (fp == NULL) {
+		err = GPG_ERR_GENERAL;
+		g_snprintf(err_str, GPGERR_BUFSIZE, "claws_fopen failed");
+		goto out_textdata;
+	}
+
+	err = gpgme_data_new_from_filepart(&sigdata, NULL, fp, task_data->sig_offset, task_data->sig_length);
+	claws_fclose(fp);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_data_new_from_filepart failed: %s", err_str);
+		goto out_textdata;
+	}
+
+	if (task_data->sig_encoding == ENC_BASE64) {
+		err = gpgme_data_set_encoding(sigdata, GPGME_DATA_ENCODING_BASE64);
+		if (err != GPG_ERR_NO_ERROR) {
+			gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+			g_warning("gpgme_data_set_encoding failed: %s\n", err_str);
+			goto out_sigdata;
+		}
+	}
+
+	if (g_task_return_error_if_cancelled(task)) {
+		debug_print("task was cancelled, aborting task:%p\n", task);
+		cancelled = TRUE;
+		goto out_sigdata;
+	}
+
+	err = gpgme_op_verify(ctx, sigdata, textdata, NULL);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_op_verify failed: %s\n", err_str);
+		goto out_sigdata;
+	}
+
+	if (g_task_return_error_if_cancelled(task)) {
+		debug_print("task was cancelled, aborting task:%p\n", task);
+		cancelled = TRUE;
+		goto out_sigdata;
+	}
+
+	gpgme_res = gpgme_op_verify_result(ctx);
+	if (gpgme_res && gpgme_res->signatures == NULL) {
+		err = GPG_ERR_SYSTEM_ERROR;
+		g_warning("no signature found");
+		g_snprintf(err_str, GPGERR_BUFSIZE, "No signature found");
+		goto out_sigdata;
+	}
+
+	task_result = g_new0(SigCheckTaskResult, 1);
+	task_result->sig_data = g_new0(SignatureData, 1);
+
+	task_result->sig_data->status = sgpgme_sigstat_gpgme_to_privacy(ctx, gpgme_res);
+	task_result->sig_data->info_short = sgpgme_sigstat_info_short(ctx, gpgme_res);
+	task_result->sig_data->info_full = sgpgme_sigstat_info_full(ctx, gpgme_res);
+
+	return_err = FALSE;
+
+out_sigdata:
+	gpgme_data_release(sigdata);
+out_textdata:
+	gpgme_data_release(textdata);
+out_textstr:
+	g_free(textstr);
+out_ctx:
+	gpgme_release(ctx);
+out:
+	if (cancelled)
+		return;
+
+	if (return_err)
+		g_task_return_new_error(task, domain, err, err_str);
+	else
+		g_task_return_pointer(task, task_result, privacy_free_sig_check_task_result);
+}
+
+gint cm_check_detached_sig_async(MimeInfo *mimeinfo,
+	GCancellable *cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data,
+	gpgme_protocol_t protocol,
+	gchar *(*get_canonical_content)(FILE *, const gchar *))
+{
+	GTask *task;
+	DetachedSigTaskData *task_data;
+	MimeInfo *parent;
+	MimeInfo *signature;
+	gchar *boundary;
+
+	parent = procmime_mimeinfo_parent(mimeinfo);
+
+	boundary = g_hash_table_lookup(parent->typeparameters, "boundary");
+	if (boundary == NULL) {
+		debug_print("failed to lookup boundary string\n");
+		return -1;
+	}
+
+	signature = (MimeInfo *) mimeinfo->node->next->data;
+
+	task_data = g_new0(DetachedSigTaskData, 1);
+
+	task_data->protocol = protocol;
+	task_data->boundary = g_strdup(boundary);
+	task_data->text_filename = g_strdup(parent->data.filename);
+	task_data->sig_filename = g_strdup(signature->data.filename);
+	task_data->sig_offset = signature->offset;
+	task_data->sig_length = signature->length;
+	task_data->sig_encoding = signature->encoding_type;
+	task_data->get_canonical_content = get_canonical_content;
+
+	task = g_task_new(NULL, cancellable, callback, user_data);
+	mimeinfo->last_sig_check_task = task;
+
+	g_task_set_task_data(task, task_data, cm_free_detached_sig_task_data);
+	debug_print("creating check sig async task:%p task_data:%p\n", task, task_data);
+	g_task_set_return_on_cancel(task, TRUE);
+	g_task_run_in_thread(task, cm_check_detached_sig);
+	g_object_unref(task);
+
+	return 0;
+}
+
 gpgme_verify_result_t sgpgme_verify_signature(gpgme_ctx_t ctx, gpgme_data_t sig, 
 					gpgme_data_t plain, gpgme_data_t dummy)
 {
@@ -312,7 +498,7 @@ gchar *sgpgme_sigstat_info_short(gpgme_ctx_t ctx, gpgme_verify_result_t status)
 	g_free(uname);
 
 	if (key)
-		gpgme_key_release(key);
+		gpgme_key_unref(key);
 
 	return result;
 }
@@ -338,6 +524,7 @@ gchar *sgpgme_sigstat_info_full(gpgme_ctx_t ctx, gpgme_verify_result_t status)
 		struct tm lt;
 		gpgme_key_t key;
 		gpgme_error_t err;
+		gpgme_user_id_t tmp;
 		const gchar *keytype, *keyid, *uid;
 		
 		err = gpgme_get_key(ctx, sig->fpr, &key, 0);
@@ -398,14 +585,14 @@ gchar *sgpgme_sigstat_info_full(gpgme_ctx_t ctx, gpgme_verify_result_t status)
 		if (sig->status != GPG_ERR_BAD_SIGNATURE) {
 			gint j = 1;
 			if (key) {
-				key->uids = key->uids ? key->uids->next : NULL;
-				while (key->uids != NULL) {
+				tmp = key->uids ? key->uids->next : NULL;
+				while (tmp != NULL) {
 					g_string_append_printf(siginfo,
 						_("                    uid \"%s\" (Validity: %s)\n"),
-						key->uids->uid,
-						key->uids->revoked==TRUE?_("Revoked"):get_validity_str(key->uids->validity));
+						tmp->uid,
+						tmp->revoked==TRUE?_("Revoked"):get_validity_str(tmp->validity));
 					j++;
-					key->uids = key->uids->next;
+					tmp = tmp->next;
 				}
 			}
 			g_string_append_printf(siginfo,_("Owner Trust: %s\n"),
@@ -446,6 +633,7 @@ gchar *sgpgme_sigstat_info_full(gpgme_ctx_t ctx, gpgme_verify_result_t status)
 		g_string_append(siginfo, "\n");
 		i++;
 		sig = sig->next;
+		gpgme_key_unref(key);
 	}
 bail:
 	ret = siginfo->str;
diff --git a/src/plugins/pgpcore/sgpgme.h b/src/plugins/pgpcore/sgpgme.h
index 78127f463..8e494af60 100644
--- a/src/plugins/pgpcore/sgpgme.h
+++ b/src/plugins/pgpcore/sgpgme.h
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 the Claws Mail team
+ * Copyright (C) 1999-2021 the Claws Mail team
  *
  * 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
@@ -24,9 +24,37 @@
 
 #include "privacy.h"
 
+#define GPGERR_BUFSIZE 128
+
+typedef struct _DetachedSigTaskData
+{
+	gpgme_protocol_t protocol;
+	gchar *boundary;
+	gchar *text_filename;
+	gchar *sig_filename;
+	guint sig_offset;
+	guint sig_length;
+	EncodingType sig_encoding;
+	gchar *(*get_canonical_content)(FILE *, const gchar *);
+} DetachedSigTaskData;
+
 void sgpgme_init(void);
 void sgpgme_done(void);
 
+void cm_free_detached_sig_task_data(gpointer data);
+
+void cm_check_detached_sig(GTask *task,
+	gpointer source_object,
+	gpointer _task_data,
+	GCancellable *cancellable);
+
+gint cm_check_detached_sig_async(MimeInfo *mimeinfo,
+	GCancellable *cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data,
+	gpgme_protocol_t protocol,
+	gchar *(*get_canonical_content)(FILE *, const gchar *));
+
 gpgme_verify_result_t sgpgme_verify_signature	(gpgme_ctx_t ctx,
 				    	 gpgme_data_t sig,
 				    	 gpgme_data_t plain,
diff --git a/src/plugins/pgpinline/claws.def b/src/plugins/pgpinline/claws.def
index 8670366b4..f09bbfa58 100644
--- a/src/plugins/pgpinline/claws.def
+++ b/src/plugins/pgpinline/claws.def
@@ -15,6 +15,8 @@ file_read_stream_to_str_no_recode
 get_mime_tmp_dir
 file_read_stream_to_str_no_recode
 my_tmpfile
+privacy_free_sig_check_task_result
+privacy_free_signature_data
 privacy_register_system
 privacy_reset_error
 privacy_set_error
diff --git a/src/plugins/pgpinline/pgpinline.c b/src/plugins/pgpinline/pgpinline.c
index 9b81fdcc9..37321be9e 100644
--- a/src/plugins/pgpinline/pgpinline.c
+++ b/src/plugins/pgpinline/pgpinline.c
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2016 Colin Leroy and the Claws Mail team
+ * Copyright (C) 1999-2021 Colin Leroy and the Claws Mail team
  *
  * 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
@@ -52,10 +52,14 @@ struct _PrivacyDataPGP
 	
 	gboolean	done_sigtest;
 	gboolean	is_signed;
-	gpgme_verify_result_t	sigstatus;
-	gpgme_ctx_t 	ctx;
 };
 
+typedef struct _PGPInlineTaskData
+{
+	gchar *rawtext;
+	gchar *charset;
+} PGPInlineTaskData;
+
 static PrivacySystem pgpinline_system;
 
 static gint pgpinline_check_signature(MimeInfo *mimeinfo);
@@ -63,26 +67,15 @@ static gint pgpinline_check_signature(MimeInfo *mimeinfo);
 static PrivacyDataPGP *pgpinline_new_privacydata()
 {
 	PrivacyDataPGP *data;
-	gpgme_error_t err;
 
 	data = g_new0(PrivacyDataPGP, 1);
 	data->data.system = &pgpinline_system;
-	data->done_sigtest = FALSE;
-	data->is_signed = FALSE;
-	data->sigstatus = NULL;
-	if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) {
-		debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err));
-        g_free(data);
-		return NULL;
-	}
 	
 	return data;
 }
 
-static void pgpinline_free_privacydata(PrivacyData *_data)
+static void pgpinline_free_privacydata(PrivacyData *data)
 {
-	PrivacyDataPGP *data = (PrivacyDataPGP *) _data;
-	gpgme_release(data->ctx);
 	g_free(data);
 }
 
@@ -144,102 +137,178 @@ static gboolean pgpinline_is_signed(MimeInfo *mimeinfo)
 	return TRUE;
 }
 
-static gint pgpinline_check_signature(MimeInfo *mimeinfo)
+static void pgpinline_free_task_data(gpointer data)
 {
-	PrivacyDataPGP *data = NULL;
-	gchar *textdata = NULL, *tmp = NULL;
-	gpgme_data_t plain = NULL, cipher = NULL;
-	gpgme_error_t err;
+	PGPInlineTaskData *task_data = (PGPInlineTaskData *)data;
 
-	cm_return_val_if_fail(mimeinfo != NULL, 0);
+	g_free(task_data->rawtext);
+	g_free(task_data->charset);
+	g_free(task_data);
+}
 
-	if (procmime_mimeinfo_parent(mimeinfo) == NULL) {
-		privacy_set_error(_("Incorrect part"));
-		return 0; /* not parent */
+static gchar *get_sig_data(gchar *rawtext, gchar *charset)
+{
+	gchar *conv;
+
+	conv = conv_codeset_strdup(rawtext, CS_UTF_8, charset);
+	if (!conv)
+		conv = conv_codeset_strdup(rawtext, CS_UTF_8, conv_get_locale_charset_str_no_utf8());
+
+	if (!conv) {
+		g_warning("can't convert charset to anything sane");
+		conv = conv_codeset_strdup(rawtext, CS_UTF_8, CS_US_ASCII);
 	}
-	if (mimeinfo->type != MIMETYPE_TEXT) {
-		privacy_set_error(_("Not a text part"));
-		debug_print("type %d\n", mimeinfo->type);
-		return 0;
+
+	return conv;
+}
+
+static void pgpinline_check_sig_task(GTask *task,
+	gpointer source_object,
+	gpointer g_task_data,
+	GCancellable *cancellable)
+{
+	PGPInlineTaskData *task_data = (PGPInlineTaskData *)g_task_data;
+	GQuark domain;
+	gpgme_ctx_t ctx;
+	gpgme_error_t err;
+	gpgme_data_t sigdata = NULL;
+	gpgme_data_t plain = NULL;
+	gpgme_verify_result_t gpgme_res;
+	gboolean return_err = TRUE;
+	gboolean cancelled = FALSE;
+	SigCheckTaskResult *task_result = NULL;
+	gchar *textstr;
+	char err_str[GPGERR_BUFSIZE];
+
+	domain = g_quark_from_static_string("claws_pgpinline");
+
+	err = gpgme_new(&ctx);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("couldn't initialize GPG context: %s", err_str);
+		goto out;
 	}
-	cm_return_val_if_fail(mimeinfo->privacy != NULL, 0);
-	data = (PrivacyDataPGP *) mimeinfo->privacy;
 
-	textdata = procmime_get_part_as_string(mimeinfo, TRUE);
+	gpgme_set_textmode(ctx, 1);
+	gpgme_set_armor(ctx, 1);
 
-	if (!textdata) {
-		g_free(textdata);
-		privacy_set_error(_("Couldn't get text data."));
-		return 0;
+	textstr = get_sig_data(task_data->rawtext, task_data->charset);
+	if (!textstr) {
+		err = GPG_ERR_GENERAL;
+		g_snprintf(err_str, GPGERR_BUFSIZE, "Couldn't convert text data to any sane charset.");
+		goto out_ctx;
 	}
 
-	/* gtk2: convert back from utf8 */
-	tmp = conv_codeset_strdup(textdata, CS_UTF_8,
-			procmime_mimeinfo_get_parameter(mimeinfo, "charset"));
-	if (!tmp) {
-		tmp = conv_codeset_strdup(textdata, CS_UTF_8,
-			conv_get_locale_charset_str_no_utf8());
+	err = gpgme_data_new_from_mem(&sigdata, textstr, strlen(textstr), 1);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_data_new_from_mem failed: %s", err_str);
+		goto out_textstr;
 	}
-	if (!tmp) {
-		g_warning("can't convert charset to anything sane");
-		tmp = conv_codeset_strdup(textdata, CS_UTF_8, CS_US_ASCII);
+
+	err = gpgme_data_new(&plain);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_data_new failed: %s", err_str);
+		goto out_sigdata;
 	}
-	g_free(textdata);
 
-	if (!tmp) {
-		privacy_set_error(_("Couldn't convert text data to any sane charset."));
-		return 0;
+	if (g_task_return_error_if_cancelled(task)) {
+		debug_print("task was cancelled, aborting task:%p\n", task);
+		cancelled = TRUE;
+		goto out_sigdata;
 	}
-	textdata = g_strdup(tmp);
-	g_free(tmp);
-	
-	if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) {
-		debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err));
-		privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
-		g_free(textdata);
-		return 0;
+
+	err = gpgme_op_verify(ctx, sigdata, NULL, plain);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_op_verify failed: %s\n", err_str);
+		goto out_plain;
 	}
-	gpgme_set_textmode(data->ctx, 1);
-	gpgme_set_armor(data->ctx, 1);
-	
-	gpgme_data_new_from_mem(&plain, textdata, (size_t)strlen(textdata), 1);
-	gpgme_data_new(&cipher);
 
-	data->sigstatus = sgpgme_verify_signature(data->ctx, plain, NULL, cipher);
-	
+	if (g_task_return_error_if_cancelled(task)) {
+		debug_print("task was cancelled, aborting task:%p\n", task);
+		cancelled = TRUE;
+		goto out_sigdata;
+	}
+
+	gpgme_res = gpgme_op_verify_result(ctx);
+	if (gpgme_res && gpgme_res->signatures == NULL) {
+		err = GPG_ERR_SYSTEM_ERROR;
+		g_warning("no signature found");
+		g_snprintf(err_str, GPGERR_BUFSIZE, "No signature found");
+		goto out_plain;
+	}
+
+	task_result = g_new0(SigCheckTaskResult, 1);
+	task_result->sig_data = g_new0(SignatureData, 1);
+
+	task_result->sig_data->status = sgpgme_sigstat_gpgme_to_privacy(ctx, gpgme_res);
+	task_result->sig_data->info_short = sgpgme_sigstat_info_short(ctx, gpgme_res);
+	task_result->sig_data->info_full = sgpgme_sigstat_info_full(ctx, gpgme_res);
+
+	return_err = FALSE;
+
+out_plain:
 	gpgme_data_release(plain);
-	gpgme_data_release(cipher);
-	
-	g_free(textdata);
-	
-	return 0;
+out_sigdata:
+	gpgme_data_release(sigdata);
+out_textstr:
+	g_free(textstr);
+out_ctx:
+	gpgme_release(ctx);
+out:
+	if (cancelled)
+		return;
+
+	if (return_err)
+		g_task_return_new_error(task, domain, err, err_str);
+	else
+		g_task_return_pointer(task, task_result, privacy_free_sig_check_task_result);
 }
 
-static SignatureStatus pgpinline_get_sig_status(MimeInfo *mimeinfo)
+static gint pgpinline_check_sig_async(MimeInfo *mimeinfo,
+	GCancellable *cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data)
 {
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
+	GTask *task;
+	PGPInlineTaskData *task_data;
+	gchar *rawtext;
+	const gchar *charset;
 
-	cm_return_val_if_fail(data != NULL, SIGNATURE_INVALID);
+	if (procmime_mimeinfo_parent(mimeinfo) == NULL) {
+		g_warning("Checking signature on incorrect part");
+		return -1;
+	}
 
-	return sgpgme_sigstat_gpgme_to_privacy(data->ctx, data->sigstatus);
-}
+	if (mimeinfo->type != MIMETYPE_TEXT) {
+		g_warning("Checking signature on a non-text part");
+		return -1;
+	}
 
-static gchar *pgpinline_get_sig_info_short(MimeInfo *mimeinfo)
-{
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
+	rawtext = procmime_get_part_as_string(mimeinfo, TRUE);
+	if (rawtext == NULL) {
+		g_warning("Failed to get part as string");
+		return -1;
+	}
 
-	cm_return_val_if_fail(data != NULL, g_strdup("Error"));
+	charset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
 
-	return sgpgme_sigstat_info_short(data->ctx, data->sigstatus);
-}
+	task_data = g_new0(PGPInlineTaskData, 1);
+	task_data->rawtext = rawtext;
+	task_data->charset = g_strdup(charset);
 
-static gchar *pgpinline_get_sig_info_full(MimeInfo *mimeinfo)
-{
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
-	
-	cm_return_val_if_fail(data != NULL, g_strdup("Error"));
+	task = g_task_new(NULL, cancellable, callback, user_data);
+	mimeinfo->last_sig_check_task = task;
 
-	return sgpgme_sigstat_info_full(data->ctx, data->sigstatus);
+	g_task_set_task_data(task, task_data, pgpinline_free_task_data);
+	debug_print("creating check sig async task:%p task_data:%p\n", task, task_data);
+	g_task_set_return_on_cancel(task, TRUE);
+	g_task_run_in_thread(task, pgpinline_check_sig_task);
+	g_object_unref(task);
+
+	return 0;
 }
 
 static gboolean pgpinline_is_encrypted(MimeInfo *mimeinfo)
@@ -301,6 +370,7 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----";
 	const gchar *end_indicator = "-----END PGP MESSAGE-----";
 	gchar *pos;
+	SignatureData *sig_data = NULL;
 	
 	if (gpgme_new(&ctx) != GPG_ERR_NO_ERROR)
 		return NULL;
@@ -329,27 +399,35 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	gpgme_data_new_from_mem(&cipher, textdata, (size_t)strlen(textdata), 1);
 
 	plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx);
-	if (sigstat && !sigstat->signatures)
-		sigstat = NULL;
 
+	if (sigstat != NULL && sigstat->signatures != NULL) {
+		sig_data = g_new0(SignatureData, 1);
+		sig_data->status = sgpgme_sigstat_gpgme_to_privacy(ctx, sigstat);
+		sig_data->info_short = sgpgme_sigstat_info_short(ctx, sigstat);
+		sig_data->info_full = sgpgme_sigstat_info_full(ctx, sigstat);
+	}
+
+	gpgme_release(ctx);
 	gpgme_data_release(cipher);
 	
 	if (plain == NULL) {
-		gpgme_release(ctx);
+		g_free(textdata);
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
-    	fname = g_strdup_printf("%s%cplaintext.%08x",
+	fname = g_strdup_printf("%s%cplaintext.%08x",
 		get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);
 
-    	if ((dstfp = claws_fopen(fname, "wb")) == NULL) {
-        	FILE_OP_ERROR(fname, "claws_fopen");
+	if ((dstfp = claws_fopen(fname, "wb")) == NULL) {
+		FILE_OP_ERROR(fname, "claws_fopen");
 		privacy_set_error(_("Couldn't open decrypted file %s"), fname);
-        	g_free(fname);
-        	gpgme_data_release(plain);
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
+		g_free(textdata);
+		g_free(fname);
+		gpgme_data_release(plain);
 		return NULL;
-    	}
+	}
 
 	src_codeset = procmime_mimeinfo_get_parameter(mimeinfo, "charset");
 	if (src_codeset == NULL)
@@ -360,7 +438,7 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 			"Content-Transfer-Encoding: 8bit\r\n"
 			"\r\n",
 			src_codeset) < 0) {
-        	FILE_OP_ERROR(fname, "fprintf");
+		FILE_OP_ERROR(fname, "fprintf");
 		privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
 		goto FILE_ERROR;
 	}
@@ -368,13 +446,13 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	/* Store any part before encrypted text */
 	pos = pgp_locate_armor_header(textdata, begin_indicator);
 	if (pos != NULL && (pos - textdata) > 0) {
-	    if (claws_fwrite(textdata, 1, pos - textdata, dstfp) < pos - textdata) {
-        	FILE_OP_ERROR(fname, "claws_fwrite");
-		privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
-		goto FILE_ERROR;
-	    }
+		if (claws_fwrite(textdata, 1, pos - textdata, dstfp) < pos - textdata) {
+			FILE_OP_ERROR(fname, "claws_fwrite");
+			privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
+			goto FILE_ERROR;
+		}
 	}
-	
+
 	if (claws_fwrite(_("\n--- Start of PGP/Inline encrypted data ---\n"), 1,
 		strlen(_("\n--- Start of PGP/Inline encrypted data ---\n")), 
 		dstfp) < strlen(_("\n--- Start of PGP/Inline encrypted data ---\n"))) {
@@ -412,12 +490,14 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	    }
 	}
 
+	g_free(textdata);
+
 	if (claws_safe_fclose(dstfp) == EOF) {
         	FILE_OP_ERROR(fname, "claws_fclose");
 		privacy_set_error(_("Couldn't close decrypted file %s"), fname);
         	g_free(fname);
         	gpgme_data_release(plain);
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	
@@ -425,16 +505,16 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 	g_free(fname);
 	
 	if (parseinfo == NULL) {
-		gpgme_release(ctx);
 		privacy_set_error(_("Couldn't scan decrypted file."));
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	decinfo = g_node_first_child(parseinfo->node) != NULL ?
 		g_node_first_child(parseinfo->node)->data : NULL;
 		
 	if (decinfo == NULL) {
-		gpgme_release(ctx);
 		privacy_set_error(_("Couldn't scan decrypted file parts."));
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -443,7 +523,7 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 
 	decinfo->tmp = TRUE;
 
-	if (sigstat != GPGME_SIG_STAT_NONE) {
+	if (sig_data != NULL) {
 		if (decinfo->privacy != NULL) {
 			data = (PrivacyDataPGP *) decinfo->privacy;
 		} else {
@@ -453,21 +533,18 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo)
 		if (data != NULL) {
 			data->done_sigtest = TRUE;
 			data->is_signed = TRUE;
-			data->sigstatus = sigstat;
-			if (data->ctx)
-				gpgme_release(data->ctx);
-			data->ctx = ctx;
+			decinfo->sig_data = sig_data;
 		}
-	} else
-		gpgme_release(ctx);
+	}
 
 	return decinfo;
 
 FILE_ERROR:
+	privacy_free_signature_data(sig_data);
+	g_free(textdata);
 	claws_fclose(dstfp);
 	g_free(fname);
 	gpgme_data_release(plain);
-	gpgme_release(ctx);
 	return NULL;
 }
 
@@ -668,6 +745,8 @@ static gboolean pgpinline_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 		if (err) {
 			debug_print("can't add key '%s'[%d] (%s)\n", fprs[i],i, gpgme_strerror(err));
 			privacy_set_error(_("Couldn't add GPG key %s, %s"), fprs[i], gpgme_strerror(err));
+			for (gint x = 0; x < i; x++)
+				gpgme_key_unref(kset[x]);
 			g_free(kset);
 			g_free(fprs);
 			return FALSE;
@@ -685,6 +764,8 @@ static gboolean pgpinline_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 		if (!msgcontent->node->children) {
 			debug_print("msgcontent->node->children NULL, bailing\n");
 			privacy_set_error(_("Malformed message"));
+			for (gint x = 0; x < i; x++)
+				gpgme_key_unref(kset[x]);
 			g_free(kset);
 			g_free(fprs);
 			return FALSE;
@@ -698,6 +779,8 @@ static gboolean pgpinline_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	if (fp == NULL) {
 		privacy_set_error(_("Couldn't create temporary file, %s"), g_strerror(errno));
 		perror("my_tmpfile");
+		for (gint x = 0; x < i; x++)
+			gpgme_key_unref(kset[x]);
 		g_free(kset);
 		g_free(fprs);
 		return FALSE;
@@ -716,6 +799,8 @@ static gboolean pgpinline_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) {
 		debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err));
 		privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
+		for (gint x = 0; x < i; x++)
+			gpgme_key_unref(kset[x]);
 		g_free(kset);
 		g_free(fprs);
 		return FALSE;
@@ -725,6 +810,8 @@ static gboolean pgpinline_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	err = gpgme_op_encrypt(ctx, kset, GPGME_ENCRYPT_ALWAYS_TRUST, gpgtext, gpgenc);
 
 	enccontent = sgpgme_data_release_and_get_mem(gpgenc, &len);
+	for (gint x = 0; x < i; x++)
+		gpgme_key_unref(kset[x]);
 	g_free(kset);
 
 	if (enccontent == NULL || len <= 0) {
@@ -769,10 +856,7 @@ static PrivacySystem pgpinline_system = {
 	pgpinline_free_privacydata,	/* free_privacydata */
 
 	pgpinline_is_signed,		/* is_signed(MimeInfo *) */
-	pgpinline_check_signature,	/* check_signature(MimeInfo *) */
-	pgpinline_get_sig_status,	/* get_sig_status(MimeInfo *) */
-	pgpinline_get_sig_info_short,	/* get_sig_info_short(MimeInfo *) */
-	pgpinline_get_sig_info_full,	/* get_sig_info_full(MimeInfo *) */
+	pgpinline_check_sig_async,
 
 	pgpinline_is_encrypted,		/* is_encrypted(MimeInfo *) */
 	pgpinline_decrypt,		/* decrypt(MimeInfo *) */
diff --git a/src/plugins/pgpinline/plugin.c b/src/plugins/pgpinline/plugin.c
index 94ebbcfce..fb5ea816b 100644
--- a/src/plugins/pgpinline/plugin.c
+++ b/src/plugins/pgpinline/plugin.c
@@ -35,7 +35,7 @@
 
 gint plugin_init(gchar **error)
 {
-	if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
+	if (!check_plugin_version(MAKE_NUMERIC_VERSION(4,0,0,441),
 				VERSION_NUMERIC, PLUGIN_NAME, error))
   		return -1;
 
diff --git a/src/plugins/pgpmime/claws.def b/src/plugins/pgpmime/claws.def
index 7f8f7001b..8dfafcefb 100644
--- a/src/plugins/pgpmime/claws.def
+++ b/src/plugins/pgpmime/claws.def
@@ -1,17 +1,18 @@
 LIBRARY CLAWS-MAIL.EXE
 EXPORTS
 canonicalize_str
-claws_fopen
-claws_fdopen
+check_plugin_version
 claws_fclose
+claws_fdopen
+claws_fopen
 claws_safe_fclose
-check_plugin_version
 debug_print_real
 debug_srcname
 file_read_stream_to_str
 generate_mime_boundary
 get_mime_tmp_dir
 my_tmpfile
+privacy_free_signature_data
 privacy_register_system
 privacy_reset_error
 privacy_set_error
diff --git a/src/plugins/pgpmime/mypgpcore.def b/src/plugins/pgpmime/mypgpcore.def
index ef8158072..a0e70c369 100644
--- a/src/plugins/pgpmime/mypgpcore.def
+++ b/src/plugins/pgpmime/mypgpcore.def
@@ -1,7 +1,11 @@
 LIBRARY PGPCORE.DLL
 EXPORTS
+cm_check_detached_sig_async
+cm_gpgme_data_rewind
 gpgmegtk_passphrase_cb
+pgp_locate_armor_header
 prefs_gpg_add_skip_encryption_warning
+prefs_gpg_auto_check_signatures
 prefs_gpg_enable_agent
 prefs_gpg_get_config
 prefs_gpg_remove_skip_encryption_warning
@@ -15,6 +19,3 @@ sgpgme_sigstat_gpgme_to_privacy
 sgpgme_sigstat_info_full
 sgpgme_sigstat_info_short
 sgpgme_verify_signature
-cm_gpgme_data_rewind
-pgp_locate_armor_header
-prefs_gpg_auto_check_signatures
diff --git a/src/plugins/pgpmime/pgpmime.c b/src/plugins/pgpmime/pgpmime.c
index 618bb6fa2..5f0ca0b96 100644
--- a/src/plugins/pgpmime/pgpmime.c
+++ b/src/plugins/pgpmime/pgpmime.c
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2016 the Claws Mail team
+ * Copyright (C) 1999-2021 the Claws Mail team
  *
  * 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
@@ -52,37 +52,22 @@ struct _PrivacyDataPGP
 	
 	gboolean	done_sigtest;
 	gboolean	is_signed;
-	gpgme_verify_result_t	sigstatus;
-	gpgme_ctx_t 	ctx;
 };
 
 static PrivacySystem pgpmime_system;
 
-static gint pgpmime_check_signature(MimeInfo *mimeinfo);
-
 static PrivacyDataPGP *pgpmime_new_privacydata()
 {
 	PrivacyDataPGP *data;
-	gpgme_error_t err;
 
 	data = g_new0(PrivacyDataPGP, 1);
 	data->data.system = &pgpmime_system;
-	data->done_sigtest = FALSE;
-	data->is_signed = FALSE;
-	data->sigstatus = NULL;
-	if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) {
-		g_warning("couldn't initialize GPG context: %s", gpgme_strerror(err));
-        g_free(data);
-		return NULL;
-	}
 	
 	return data;
 }
 
-static void pgpmime_free_privacydata(PrivacyData *_data)
+static void pgpmime_free_privacydata(PrivacyData *data)
 {
-	PrivacyDataPGP *data = (PrivacyDataPGP *) _data;
-	gpgme_release(data->ctx);
 	g_free(data);
 }
 
@@ -139,7 +124,6 @@ static gboolean pgpmime_is_signed(MimeInfo *mimeinfo)
 
 static gchar *get_canonical_content(FILE *fp, const gchar *boundary)
 {
-	gchar *ret;
 	GString *textbuffer;
 	guint boundary_len;
 	gchar buf[BUFFSIZE];
@@ -162,106 +146,20 @@ static gchar *get_canonical_content(FILE *fp, const gchar *boundary)
 	}
 	g_string_truncate(textbuffer, textbuffer->len - 2);
 		
-	ret = textbuffer->str;
-	g_string_free(textbuffer, FALSE);
-
-	return ret;
+	return g_string_free(textbuffer, FALSE);
 }
 
-static gint pgpmime_check_signature(MimeInfo *mimeinfo)
+static gint pgpmime_check_sig_async(MimeInfo *mimeinfo,
+	GCancellable *cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data)
 {
-	PrivacyDataPGP *data;
-	MimeInfo *parent, *signature;
-	FILE *fp;
-	gchar *boundary;
-	gchar *textstr;
-	gpgme_data_t sigdata = NULL, textdata = NULL;
-	gpgme_error_t err;
-	cm_return_val_if_fail(mimeinfo != NULL, -1);
-	cm_return_val_if_fail(mimeinfo->privacy != NULL, -1);
-	data = (PrivacyDataPGP *) mimeinfo->privacy;
-	if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) {
-		debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err));
-		privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
-		return 0;
-	}
-
-	
-	debug_print("Checking PGP/MIME signature\n");
-
-	err = gpgme_set_protocol(data->ctx, GPGME_PROTOCOL_OpenPGP);
-
-	if (err) {
-		debug_print ("gpgme_set_protocol failed: %s\n",
-                   gpgme_strerror (err));
-	}
-	parent = procmime_mimeinfo_parent(mimeinfo);
-
-	fp = claws_fopen(parent->data.filename, "rb");
-	cm_return_val_if_fail(fp != NULL, SIGNATURE_INVALID);
-	
-	boundary = g_hash_table_lookup(parent->typeparameters, "boundary");
-	if (!boundary) {
-		privacy_set_error(_("Signature boundary not found."));
-		claws_fclose(fp);
-		return 0;
-	}
-	textstr = get_canonical_content(fp, boundary);
-
-	err = gpgme_data_new_from_mem(&textdata, textstr, (size_t)strlen(textstr), 0);
-	if (err) {
-		debug_print ("gpgme_data_new_from_mem failed: %s\n",
-                   gpgme_strerror (err));
-	}
-	signature = (MimeInfo *) mimeinfo->node->next->data;
-	sigdata = sgpgme_data_from_mimeinfo(signature);
-
-	err = 0;
-	if (signature->encoding_type == ENC_BASE64) {
-		err = gpgme_data_set_encoding (sigdata, GPGME_DATA_ENCODING_BASE64);
-	}
-	
-	if (err) {
-		debug_print ("gpgme_data_set_encoding failed: %s\n",
-			gpgme_strerror (err));
-	}
-
-	data->sigstatus =
-		sgpgme_verify_signature	(data->ctx, sigdata, textdata, NULL);
-
-	gpgme_data_release(sigdata);
-	gpgme_data_release(textdata);
-	g_free(textstr);
-	claws_fclose(fp);
-	
-	return 0;
-}
-
-static SignatureStatus pgpmime_get_sig_status(MimeInfo *mimeinfo)
-{
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
-	
-	cm_return_val_if_fail(data != NULL, SIGNATURE_INVALID);
-
-	return sgpgme_sigstat_gpgme_to_privacy(data->ctx, data->sigstatus);
-}
-
-static gchar *pgpmime_get_sig_info_short(MimeInfo *mimeinfo)
-{
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
-	
-	cm_return_val_if_fail(data != NULL, g_strdup("Error"));
-
-	return sgpgme_sigstat_info_short(data->ctx, data->sigstatus);
-}
-
-static gchar *pgpmime_get_sig_info_full(MimeInfo *mimeinfo)
-{
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
-
-	cm_return_val_if_fail(data != NULL, g_strdup("Error"));
-
-	return sgpgme_sigstat_info_full(data->ctx, data->sigstatus);
+	return cm_check_detached_sig_async(mimeinfo,
+		cancellable,
+		callback,
+		user_data,
+		GPGME_PROTOCOL_OpenPGP,
+		get_canonical_content);
 }
 
 static gboolean pgpmime_is_encrypted(MimeInfo *mimeinfo)
@@ -325,6 +223,7 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	gchar *chars;
 	size_t len;
 	gpgme_error_t err;
+	SignatureData *sig_data = NULL;
 
 	if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) {
 		debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err));
@@ -339,33 +238,41 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	cipher = sgpgme_data_from_mimeinfo(encinfo);
 	plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx);
 
+	if (sigstat != NULL && sigstat->signatures != NULL) {
+		sig_data = g_new0(SignatureData, 1);
+		sig_data->status = sgpgme_sigstat_gpgme_to_privacy(ctx, sigstat);
+		sig_data->info_short = sgpgme_sigstat_info_short(ctx, sigstat);
+		sig_data->info_full = sgpgme_sigstat_info_full(ctx, sigstat);
+	}
+
+	gpgme_release(ctx);
 	gpgme_data_release(cipher);
 	if (plain == NULL) {
 		debug_print("plain is null!\n");
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
-    	fname = g_strdup_printf("%s%cplaintext.%08x",
+	fname = g_strdup_printf("%s%cplaintext.%08x",
 		get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);
 
-    	if ((dstfp = claws_fopen(fname, "wb")) == NULL) {
-        	FILE_OP_ERROR(fname, "claws_fopen");
+	if ((dstfp = claws_fopen(fname, "wb")) == NULL) {
+		FILE_OP_ERROR(fname, "claws_fopen");
 		privacy_set_error(_("Couldn't open decrypted file %s"), fname);
-        	g_free(fname);
-        	gpgme_data_release(plain);
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
+		g_free(fname);
+		gpgme_data_release(plain);
 		debug_print("can't open!\n");
 		return NULL;
-    	}
+	}
 
 	if (fprintf(dstfp, "MIME-Version: 1.0\n") < 0) {
-        	FILE_OP_ERROR(fname, "fprintf");
+		FILE_OP_ERROR(fname, "fprintf");
 		claws_fclose(dstfp);
 		privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
-        	g_free(fname);
-        	gpgme_data_release(plain);
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
+		g_free(fname);
+		gpgme_data_release(plain);
 		debug_print("can't open!\n");
 		return NULL;
 	}
@@ -373,13 +280,13 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	chars = sgpgme_data_release_and_get_mem(plain, &len);
 	if (len > 0) {
 		if (claws_fwrite(chars, 1, len, dstfp) < len) {
-        		FILE_OP_ERROR(fname, "claws_fwrite");
+			FILE_OP_ERROR(fname, "claws_fwrite");
 			g_free(chars);
 			claws_fclose(dstfp);
 			privacy_set_error(_("Couldn't write to decrypted file %s"), fname);
-        		g_free(fname);
-        		gpgme_data_release(plain);
-			gpgme_release(ctx);
+			privacy_free_signature_data(sig_data);
+			g_free(fname);
+			gpgme_data_release(plain);
 			debug_print("can't open!\n");
 			return NULL;
 		}
@@ -387,11 +294,11 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	g_free(chars);
 
 	if (claws_safe_fclose(dstfp) == EOF) {
-        	FILE_OP_ERROR(fname, "claws_fclose");
+		FILE_OP_ERROR(fname, "claws_fclose");
 		privacy_set_error(_("Couldn't close decrypted file %s"), fname);
-        	g_free(fname);
-        	gpgme_data_release(plain);
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
+		g_free(fname);
+		gpgme_data_release(plain);
 		debug_print("can't open!\n");
 		return NULL;
 	}
@@ -399,15 +306,15 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 	parseinfo = procmime_scan_file(fname);
 	g_free(fname);
 	if (parseinfo == NULL) {
-		gpgme_release(ctx);
 		privacy_set_error(_("Couldn't parse decrypted file."));
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	decinfo = g_node_first_child(parseinfo->node) != NULL ?
 		g_node_first_child(parseinfo->node)->data : NULL;
 	if (decinfo == NULL) {
 		privacy_set_error(_("Couldn't parse decrypted file parts."));
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -416,23 +323,20 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo)
 
 	decinfo->tmp = TRUE;
 
-	if (sigstat != NULL && sigstat->signatures != NULL) {
+	if (sig_data != NULL) {
 		if (decinfo->privacy != NULL) {
 			data = (PrivacyDataPGP *) decinfo->privacy;
 		} else {
 			data = pgpmime_new_privacydata();
-			decinfo->privacy = (PrivacyData *) data;	
+			decinfo->privacy = (PrivacyData *) data;
 		}
+
 		if (data != NULL) {
 			data->done_sigtest = TRUE;
 			data->is_signed = TRUE;
-			data->sigstatus = sigstat;
-			if (data->ctx)
-				gpgme_release(data->ctx);
-			data->ctx = ctx;
+			decinfo->sig_data = sig_data;
 		}
-	} else
-		gpgme_release(ctx);
+	}
 
 	return decinfo;
 }
@@ -588,6 +492,7 @@ gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *fr
 		privacy_set_error(_("Data signing failed, no contents."));
 		g_free(micalg);
 		g_free(sigcontent);
+		gpgme_release(ctx);
 		return FALSE;
 	}
 
@@ -651,8 +556,7 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 		i++;
 	}
 	
-	kset = g_malloc(sizeof(gpgme_key_t)*(i+1));
-	memset(kset, 0, sizeof(gpgme_key_t)*(i+1));
+	kset = g_malloc0(sizeof(gpgme_key_t)*(i+1));
 	if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) {
 		debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err));
 		privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err));
@@ -667,8 +571,11 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 		if (err) {
 			debug_print("can't add key '%s'[%d] (%s)\n", fprs[i],i, gpgme_strerror(err));
 			privacy_set_error(_("Couldn't add GPG key %s, %s"), fprs[i], gpgme_strerror(err));
+			for (gint x = 0; x < i; x++)
+				gpgme_key_unref(kset[x]);
 			g_free(kset);
 			g_free(fprs);
+			gpgme_release(ctx);
 			return FALSE;
 		}
 		debug_print("found %s at %d\n", fprs[i], i);
@@ -698,9 +605,12 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	if (fp == NULL) {
 		perror("my_tmpfile");
 		privacy_set_error(_("Couldn't create temporary file, %s"), g_strerror(errno));
+		for (gint x = 0; x < i; x++)
+			gpgme_key_unref(kset[x]);
 		g_free(kset);
 		g_free(boundary);
 		g_free(fprs);
+		gpgme_release(ctx);
 		return FALSE;
 	}
 	procmime_write_mimeinfo(encmultipart, fp);
@@ -723,6 +633,8 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	enccontent = sgpgme_data_release_and_get_mem(gpgenc, &len);
 	gpgme_data_release(gpgtext);
 	g_free(textstr);
+	for (gint x = 0; x < i; x++)
+		gpgme_key_unref(kset[x]);
 	g_free(kset);
 
 	if (enccontent == NULL || len <= 0) {
@@ -772,10 +684,7 @@ static PrivacySystem pgpmime_system = {
 	pgpmime_free_privacydata,	/* free_privacydata */
 
 	pgpmime_is_signed,		/* is_signed(MimeInfo *) */
-	pgpmime_check_signature,	/* check_signature(MimeInfo *) */
-	pgpmime_get_sig_status,		/* get_sig_status(MimeInfo *) */
-	pgpmime_get_sig_info_short,	/* get_sig_info_short(MimeInfo *) */
-	pgpmime_get_sig_info_full,	/* get_sig_info_full(MimeInfo *) */
+	pgpmime_check_sig_async,
 
 	pgpmime_is_encrypted,		/* is_encrypted(MimeInfo *) */
 	pgpmime_decrypt,		/* decrypt(MimeInfo *) */
diff --git a/src/plugins/pgpmime/plugin.c b/src/plugins/pgpmime/plugin.c
index fe339cbc8..3ca210324 100644
--- a/src/plugins/pgpmime/plugin.c
+++ b/src/plugins/pgpmime/plugin.c
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 the Claws Mail team
+ * Copyright (C) 1999-2021 the Claws Mail team
  *
  * 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,7 +35,7 @@
 
 gint plugin_init(gchar **error)
 {
-	if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
+	if (!check_plugin_version(MAKE_NUMERIC_VERSION(4,0,0,441),
 				VERSION_NUMERIC, PLUGIN_NAME, error))
 		return -1;
 
diff --git a/src/plugins/smime/claws.def b/src/plugins/smime/claws.def
index 351805937..77e8fd836 100644
--- a/src/plugins/smime/claws.def
+++ b/src/plugins/smime/claws.def
@@ -3,11 +3,11 @@ EXPORTS
 alertpanel_error
 canonicalize_file_replace
 canonicalize_str
-claws_fopen
-claws_fdopen
+check_plugin_version
 claws_fclose
+claws_fdopen
+claws_fopen
 claws_safe_fclose
-check_plugin_version
 claws_unlink
 debug_print_real
 debug_srcname
@@ -18,12 +18,15 @@ generate_mime_boundary
 get_mime_tmp_dir
 get_tmp_file
 my_tmpfile
+privacy_free_sig_check_task_result
+privacy_free_signature_data
 privacy_register_system
 privacy_set_error
 privacy_unregister_system
 procmime_decode_content
 procmime_encode_content
 procmime_get_part
+procmime_get_part_as_string
 procmime_mimeinfo_free_all
 procmime_mimeinfo_get_parameter
 procmime_mimeinfo_new
diff --git a/src/plugins/smime/mypgpcore.def b/src/plugins/smime/mypgpcore.def
index 44dd8d22e..f2a911c61 100644
--- a/src/plugins/smime/mypgpcore.def
+++ b/src/plugins/smime/mypgpcore.def
@@ -1,7 +1,10 @@
 LIBRARY PGPCORE.DLL
 EXPORTS
+cm_check_detached_sig_async
+cm_gpgme_data_rewind
 gpgmegtk_passphrase_cb
 prefs_gpg_add_skip_encryption_warning
+prefs_gpg_auto_check_signatures
 prefs_gpg_enable_agent
 prefs_gpg_get_config
 prefs_gpg_remove_skip_encryption_warning
@@ -15,5 +18,3 @@ sgpgme_sigstat_gpgme_to_privacy
 sgpgme_sigstat_info_full
 sgpgme_sigstat_info_short
 sgpgme_verify_signature
-cm_gpgme_data_rewind
-prefs_gpg_auto_check_signatures
diff --git a/src/plugins/smime/plugin.c b/src/plugins/smime/plugin.c
index d31c1b339..05c1db38e 100644
--- a/src/plugins/smime/plugin.c
+++ b/src/plugins/smime/plugin.c
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 Colin Leroy <colin at colino.net> and 
+ * Copyright (C) 1999-2021 Colin Leroy <colin at colino.net> and 
  * the Claws Mail team
  *
  * This program is free software; you can redistribute it and/or modify
@@ -32,10 +32,12 @@
 #include "common/claws.h"
 #include "smime.h"
 
+#define PLUGIN_NAME (_("S/MIME"))
+
 gint plugin_init(gchar **error)
 {
-	if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
-				VERSION_NUMERIC, _("S/MIME"), error))
+	if (!check_plugin_version(MAKE_NUMERIC_VERSION(4,0,0,441),
+				VERSION_NUMERIC, PLUGIN_NAME, error))
 		return -1;
 
 	smime_init();
@@ -51,7 +53,7 @@ gboolean plugin_done(void)
 
 const gchar *plugin_name(void)
 {
-	return _("S/MIME");
+	return PLUGIN_NAME;
 }
 
 const gchar *plugin_desc(void)
diff --git a/src/plugins/smime/smime.c b/src/plugins/smime/smime.c
index 324fc67df..f135714c8 100644
--- a/src/plugins/smime/smime.c
+++ b/src/plugins/smime/smime.c
@@ -1,6 +1,6 @@
 /* 
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2016 Colin Leroy and the Claws Mail team
+ * Copyright (C) 1999-2021 Colin Leroy and the Claws Mail team
  *
  * 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
@@ -52,41 +52,34 @@ struct _PrivacyDataPGP
 	
 	gboolean	done_sigtest;
 	gboolean	is_signed;
-	gpgme_verify_result_t	sigstatus;
-	gpgme_ctx_t 	ctx;
+	gboolean	inserted_mimeinfo;
 };
 
-static PrivacySystem smime_system;
+typedef struct _PKCS7MimeTaskData {
+	gchar *textstr;
+	EncodingType encoding;
+	gboolean create_mimeinfo;
+} PKCS7MimeTaskData;
 
-static gint smime_check_signature(MimeInfo *mimeinfo);
+static PrivacySystem smime_system;
 
 static PrivacyDataPGP *smime_new_privacydata()
 {
 	PrivacyDataPGP *data;
-	gpgme_ctx_t 	ctx;
-
-	if (gpgme_new(&ctx) != GPG_ERR_NO_ERROR) {
-		debug_print("gpgme_new failed\n");
-		return NULL;
-	}
 
 	data = g_new0(PrivacyDataPGP, 1);
 	data->data.system = &smime_system;
-	data->done_sigtest = FALSE;
-	data->is_signed = FALSE;
-	data->sigstatus = NULL;
-	data->ctx = ctx;
 	
 	return data;
 }
 
-static void smime_free_privacydata(PrivacyData *_data)
+static void smime_free_privacydata(PrivacyData *data)
 {
-	PrivacyDataPGP *data = (PrivacyDataPGP *) _data;
-	gpgme_release(data->ctx);
 	g_free(data);
 }
 
+static gint check_pkcs7_mime_sig(MimeInfo *, GCancellable *, GAsyncReadyCallback, gpointer);
+
 static gboolean smime_is_signed(MimeInfo *mimeinfo)
 {
 	MimeInfo *parent;
@@ -114,7 +107,7 @@ static gboolean smime_is_signed(MimeInfo *mimeinfo)
 
 			data->done_sigtest = TRUE;
 			data->is_signed = TRUE;
-			smime_check_signature(mimeinfo);
+			check_pkcs7_mime_sig(mimeinfo, NULL, NULL, NULL);
 			return TRUE;
 		}
 	}
@@ -163,7 +156,6 @@ static gboolean smime_is_signed(MimeInfo *mimeinfo)
 
 static gchar *get_canonical_content(FILE *fp, const gchar *boundary)
 {
-	gchar *ret;
 	GString *textbuffer;
 	guint boundary_len = 0;
 	gchar buf[BUFFSIZE];
@@ -188,190 +180,338 @@ static gchar *get_canonical_content(FILE *fp, const gchar *boundary)
 	}
 	g_string_truncate(textbuffer, textbuffer->len - 2);
 		
-	ret = textbuffer->str;
-	g_string_free(textbuffer, FALSE);
+	return g_string_free(textbuffer, FALSE);
+}
 
-	return ret;
+static void free_pkcs7_mime_task_data(gpointer data)
+{
+	PKCS7MimeTaskData *task_data = (PKCS7MimeTaskData *)data;
+
+	g_free(task_data->textstr);
+	g_free(task_data);
 }
 
-static gint smime_check_signature(MimeInfo *mimeinfo)
+static gboolean create_mimeinfo_for_plaintext(const GString *verified, MimeInfo **created)
 {
-	PrivacyDataPGP *data;
-	MimeInfo *parent, *signature;
-	FILE *fp;
-	gchar *boundary;
-	gchar *textstr = NULL;
-	const gchar *tmpstr;
-	gpgme_data_t sigdata = NULL, textdata = NULL;
+	gchar *tmpfile;
+	MimeInfo *newinfo = NULL;
+	MimeInfo *decinfo = NULL;
+
+	tmpfile = get_tmp_file();
+
+	str_write_to_file(verified->str, tmpfile, TRUE);
+	newinfo = procmime_scan_file(tmpfile);
+	g_free(tmpfile);
+	decinfo = g_node_first_child(newinfo->node) != NULL ?
+		g_node_first_child(newinfo->node)->data : NULL;
+
+	if (decinfo == NULL)
+		return FALSE;
+
+	g_node_unlink(decinfo->node);
+	procmime_mimeinfo_free_all(&newinfo);
+	decinfo->tmp = TRUE;
+
+	*created = decinfo;
+	return TRUE;
+}
+
+static void check_pkcs7_mime_sig_task(GTask *task,
+	gpointer source_object,
+	gpointer _task_data,
+	GCancellable *cancellable)
+{
+	PKCS7MimeTaskData *task_data = (PKCS7MimeTaskData *)_task_data;
+	GQuark domain;
+	gpgme_ctx_t ctx;
 	gpgme_error_t err;
-	EncodingType oldenc = ENC_BINARY;
+	gpgme_data_t sigdata = NULL;
+	gpgme_data_t plain;
+	gpgme_verify_result_t gpgme_res;
+	size_t len;
+	gboolean return_err = TRUE;
+	gboolean cancelled = FALSE;
+	SigCheckTaskResult *task_result = NULL;
+	MimeInfo *created = NULL;
+	GString *verified;
+	gchar *tmp;
+	char err_str[GPGERR_BUFSIZE];
 
-	cm_return_val_if_fail(mimeinfo != NULL, -1);
-	cm_return_val_if_fail(mimeinfo->privacy != NULL, -1);
+	domain = g_quark_from_static_string("claws_smime");
 
-	data = (PrivacyDataPGP *) mimeinfo->privacy;
+	err = gpgme_new(&ctx);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("couldn't initialize GPG context: %s", err_str);
+		goto out;
+	}
 
-	if (!data->ctx) {
-		if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) {
-			debug_print("gpgme_new failed: %s\n",
-				gpgme_strerror(err));
-			return -1;
+	err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("couldn't set GPG protocol: %s", err_str);
+		goto out_ctx;
+	}
+
+	err = gpgme_data_new_from_mem(&sigdata,
+		task_data->textstr,
+		task_data->textstr ? strlen(task_data->textstr) : 0,
+		0);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_data_new_from_mem failed: %s", err_str);
+		goto out_ctx;
+	}
+
+	if (task_data->encoding == ENC_BASE64) {
+		err = gpgme_data_set_encoding (sigdata, GPGME_DATA_ENCODING_BASE64);
+		if (err != GPG_ERR_NO_ERROR) {
+			gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+			g_warning("gpgme_data_set_encoding failed: %s\n", err_str);
+			goto out_sigdata;
 		}
 	}
 
-	debug_print("Checking S/MIME signature\n");
+	err = gpgme_data_new(&plain);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_data_new failed: %s", err_str);
+		goto out_sigdata;
+	}
 
-	err = gpgme_set_protocol(data->ctx, GPGME_PROTOCOL_CMS);
+	if (g_task_return_error_if_cancelled(task)) {
+		debug_print("task was cancelled, aborting task:%p\n", task);
+		cancelled = TRUE;
+		goto out_sigdata;
+	}
 
-	if (err) {
-		debug_print ("gpgme_set_protocol failed: %s\n",
-                   gpgme_strerror (err));
+	err = gpgme_op_verify(ctx, sigdata, NULL, plain);
+	if (err != GPG_ERR_NO_ERROR) {
+		gpgme_strerror_r(err, err_str, GPGERR_BUFSIZE);
+		g_warning("gpgme_op_verify failed: %s\n", err_str);
+		goto out_plain;
 	}
-	parent = procmime_mimeinfo_parent(mimeinfo);
 
-	fp = claws_fopen(parent->data.filename, "rb");
-	cm_return_val_if_fail(fp != NULL, SIGNATURE_INVALID);
-	
-	boundary = g_hash_table_lookup(parent->typeparameters, "boundary");
-	if (!boundary) {
-		gchar *tmpfile = get_tmp_file();
-		debug_print("no boundary\n");
-		if (tmpfile) {
-			if (mimeinfo->encoding_type != ENC_BASE64) {
-				procmime_encode_content(mimeinfo, ENC_BASE64);
-			}
-			oldenc = mimeinfo->encoding_type;
-			if (mimeinfo->encoding_type == ENC_BASE64)
-				mimeinfo->encoding_type = ENC_BINARY;
-			if (procmime_get_part(tmpfile, mimeinfo) == 0) {
-				textstr = file_read_to_str(tmpfile);
-			} else {
-				textstr = NULL;
-			}
-			if (mimeinfo->encoding_type != oldenc)
-				mimeinfo->encoding_type = oldenc;
-		}
-		g_free(tmpfile);
-	} else {
-		textstr = get_canonical_content(fp, boundary);
+	if (g_task_return_error_if_cancelled(task)) {
+		debug_print("task was cancelled, aborting task:%p\n", task);
+		cancelled = TRUE;
+		goto out_sigdata;
 	}
-	err = gpgme_data_new_from_mem(&textdata, textstr, textstr?strlen(textstr):0, 0);
-	
-	if (err) {
-		debug_print ("gpgme_data_new_from_mem failed: %s\n",
-                   gpgme_strerror (err));
+
+	gpgme_res = gpgme_op_verify_result(ctx);
+	if (gpgme_res && gpgme_res->signatures == NULL) {
+		err = GPG_ERR_SYSTEM_ERROR;
+		g_warning("no signature found");
+		g_snprintf(err_str, GPGERR_BUFSIZE, "No signature found");
+		goto out_plain;
 	}
 
-	if (!g_ascii_strcasecmp(mimeinfo->subtype, "pkcs7-mime") ||
-	    !g_ascii_strcasecmp(mimeinfo->subtype, "x-pkcs7-mime")) {
-		tmpstr = procmime_mimeinfo_get_parameter(mimeinfo, "smime-type");
-		if (tmpstr && !g_ascii_strcasecmp(tmpstr, "signed-data")) {
-			gpgme_data_t cipher;
-			size_t len;
-			if (oldenc == ENC_BASE64)
-				gpgme_data_set_encoding (textdata, GPGME_DATA_ENCODING_BASE64);
-			gpgme_data_new(&cipher);
-			data->sigstatus =
-				sgpgme_verify_signature	(data->ctx, textdata, NULL, cipher);
-			gpgme_data_release(textdata);
-			g_free(textstr);
-			cm_gpgme_data_rewind(cipher);
-			textstr = sgpgme_data_release_and_get_mem(cipher, &len);
-			claws_fclose(fp);
-			if (textstr && len > 0)
-				textstr[len-1]='\0';
-
-			if (textstr && len) {
-				gchar *tmp_file = get_tmp_file();
-				MimeInfo *newinfo = NULL, *decinfo = NULL, *parentinfo = NULL;
-
-				str_write_to_file(textstr, tmp_file, TRUE);
-				newinfo = procmime_scan_file(tmp_file);
-				decinfo = g_node_first_child(newinfo->node) != NULL ?
-					g_node_first_child(newinfo->node)->data : NULL;
-
-				if (decinfo == NULL) {
-					g_free(textstr);
-					return -1;
-				}
-
-				g_node_unlink(decinfo->node);
-				procmime_mimeinfo_free_all(&newinfo);
-				decinfo->tmp = TRUE;
-				parentinfo = procmime_mimeinfo_parent(mimeinfo);
-
-				if (parentinfo->type == MIMETYPE_MESSAGE && 
-				    !strcmp(parentinfo->subtype, "rfc822")) {
-					procmime_decode_content(parentinfo);
-					procmime_encode_content(parentinfo, ENC_BASE64);
-					procmime_encode_content(parentinfo, ENC_8BIT);
-					if (parentinfo->content == MIMECONTENT_MEM) {
-						gint newlen = 
-							(gint)(strstr(parentinfo->data.mem, "\n\n") - parentinfo->data.mem);
-						if (newlen > 0)
-							parentinfo->length = newlen;
-					}
-				}
-				g_node_prepend(parentinfo->node, decinfo->node);
-				g_free(textstr);
-				return 0;
-			} else {
-				if (textstr)
-					g_free(textstr);
-				return -1;
-			}
+	if (task_data->create_mimeinfo) {
+		tmp = gpgme_data_release_and_get_mem(plain, &len);
+		if (!tmp) {
+			debug_print("S/MIME signed message had no plaintext\n");
+			goto out_sigdata;
 		}
-	}
 
-	signature = (MimeInfo *) mimeinfo->node->next->data;
-	sigdata = sgpgme_data_from_mimeinfo(signature);
+		verified = g_string_new_len(tmp, len);
+		gpgme_free(tmp);
 
-	err = 0;
-	if (signature->encoding_type == ENC_BASE64) {
-		err = gpgme_data_set_encoding (sigdata, GPGME_DATA_ENCODING_BASE64);
-	}
-	
-	if (err) {
-		debug_print ("gpgme_data_set_encoding failed: %s\n",
-			gpgme_strerror (err));
+		if (!create_mimeinfo_for_plaintext(verified, &created)) {
+			g_warning("Failed to create new mimeinfo from plaintext");
+			g_string_free(verified, TRUE);
+			goto out_sigdata;
+		}
+
+		g_string_free(verified, TRUE);
+	} else {
+		gpgme_data_release(plain);
 	}
 
-	data->sigstatus =
-		sgpgme_verify_signature	(data->ctx, sigdata, textdata, NULL);
+	task_result = g_new0(SigCheckTaskResult, 1);
+	task_result->sig_data = g_new0(SignatureData, 1);
+
+	task_result->sig_data->status = sgpgme_sigstat_gpgme_to_privacy(ctx, gpgme_res);
+	task_result->sig_data->info_short = sgpgme_sigstat_info_short(ctx, gpgme_res);
+	task_result->sig_data->info_full = sgpgme_sigstat_info_full(ctx, gpgme_res);
+
+	task_result->newinfo = created;
+	return_err = FALSE;
+
+	goto out_sigdata;
 
+out_plain:
+	gpgme_data_release(plain);
+out_sigdata:
 	gpgme_data_release(sigdata);
-	gpgme_data_release(textdata);
-	g_free(textstr);
-	claws_fclose(fp);
-	
-	return 0;
+out_ctx:
+	gpgme_release(ctx);
+out:
+	if (cancelled)
+		return;
+
+	if (return_err)
+		g_task_return_new_error(task, domain, err, err_str);
+	else
+		g_task_return_pointer(task, task_result, privacy_free_sig_check_task_result);
 }
 
-static SignatureStatus smime_get_sig_status(MimeInfo *mimeinfo)
+/* Check PKCS7-MIME signed-data type signature either synchronously or asynchronously.
+ * Check it asynchronously if the caller provides a callback.
+ * If the caller does not provide a callback, and we have not already done so, create
+ * and insert a new MimeInfo for the plaintext data returned by the sig verification.
+ */
+static gint check_pkcs7_mime_sig(MimeInfo *mimeinfo,
+	GCancellable *_cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data)
 {
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
-	
-	cm_return_val_if_fail(data != NULL, SIGNATURE_INVALID);
+	MimeInfo *parent;
+	const gchar *tmp;
+	EncodingType real_enc;
+	gchar *textstr = NULL;
+	PrivacyDataPGP *privacy_data;
+	GCancellable *cancellable;
+	GTask *task;
+	PKCS7MimeTaskData *task_data;
+	SigCheckTaskResult *task_result;
+	GError *error;
+	gboolean unref_cancellable = FALSE;
 
-	return sgpgme_sigstat_gpgme_to_privacy(data->ctx, data->sigstatus);
-}
+	debug_print("Checking pkcs7-mime signature\n");
 
-static gchar *smime_get_sig_info_short(MimeInfo *mimeinfo)
-{
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
-	
-	cm_return_val_if_fail(data != NULL, g_strdup("Error"));
+	parent = procmime_mimeinfo_parent(mimeinfo);
+	tmp = g_hash_table_lookup(parent->typeparameters, "boundary");
+	if (tmp) {
+		g_warning("Unexpected S/MIME message format subtype:%s boundary:%s",
+			mimeinfo->subtype, tmp);
+		return -1;
+	}
+
+	if (g_ascii_strcasecmp(mimeinfo->subtype, "pkcs7-mime") &&
+		g_ascii_strcasecmp(mimeinfo->subtype, "x-pkcs7-mime"))
+	{
+		g_warning("Unexpected S/MIME subtype:%s", mimeinfo->subtype);
+		return -1;
+	}
+
+	tmp = procmime_mimeinfo_get_parameter(mimeinfo, "smime-type");
+	if (!tmp || g_ascii_strcasecmp(tmp, "signed-data")) {
+		g_warning("Unexpected S/MIME smime-type parameter:%s", tmp);
+		return -1;
+	}
+
+	real_enc = mimeinfo->encoding_type;
+	mimeinfo->encoding_type = ENC_BINARY;
+	textstr = procmime_get_part_as_string(mimeinfo, TRUE);
+	mimeinfo->encoding_type = real_enc;
+	if (!textstr) {
+		g_warning("Failed to get PKCS7-Mime signature data");
+		return -1;
+	}
+
+	privacy_data = (PrivacyDataPGP *)mimeinfo->privacy;
+
+	task_data = g_new0(PKCS7MimeTaskData, 1);
+	task_data->textstr = textstr;
+	task_data->encoding = mimeinfo->encoding_type;
+
+	if (!callback && !privacy_data->inserted_mimeinfo)
+		task_data->create_mimeinfo = TRUE;
+
+	if (_cancellable != NULL) {
+		cancellable = _cancellable;
+	} else {
+		cancellable = g_cancellable_new();
+		unref_cancellable = TRUE;
+	}
+
+	task = g_task_new(NULL, cancellable, callback, user_data);
+	mimeinfo->last_sig_check_task = task;
+
+	g_task_set_task_data(task, task_data, free_pkcs7_mime_task_data);
+	g_task_set_return_on_cancel(task, TRUE);
+
+	if (callback) {
+		debug_print("creating check sig async task:%p task_data:%p\n", task, task_data);
+		g_task_run_in_thread(task, check_pkcs7_mime_sig_task);
+		g_object_unref(task);
+		return 0;
+	}
+
+	debug_print("creating check sig sync task:%p task_data:%p\n", task, task_data);
+	g_task_run_in_thread_sync(task, check_pkcs7_mime_sig_task);
+	mimeinfo->last_sig_check_task = NULL;
+
+	task_result = g_task_propagate_pointer(task, &error);
+	g_object_unref(task);
+	if (unref_cancellable)
+		g_object_unref(cancellable);
+
+	if (mimeinfo->sig_data) {
+		privacy_free_signature_data(mimeinfo->sig_data);
+		mimeinfo->sig_data = NULL;
+	}
+
+	if (task_result == NULL) {
+		debug_print("sig check task propagated NULL task:%p GError: domain:%s code:%d message:\"%s\"\n",
+			task, g_quark_to_string(error->domain), error->code, error->message);
+		g_error_free(error);
+		return -1;
+	}
+
+	mimeinfo->sig_data = task_result->sig_data;
 
-	return sgpgme_sigstat_info_short(data->ctx, data->sigstatus);
+	if (task_result->newinfo) {
+		if (parent->type == MIMETYPE_MESSAGE && !strcmp(parent->subtype, "rfc822")) {
+			if (parent->content == MIMECONTENT_MEM) {
+				gint newlen = (gint)(strstr(parent->data.mem, "\n\n") - parent->data.mem);
+				if (newlen > 0)
+				parent->length = newlen;
+			}
+		}
+
+		g_node_prepend(parent->node, task_result->newinfo->node);
+		privacy_data->inserted_mimeinfo = TRUE;
+	}
+
+	/* Only free the task result struct, not the SigData and MimeInfo */
+	g_free(task_result);
+
+	return 1;
 }
 
-static gchar *smime_get_sig_info_full(MimeInfo *mimeinfo)
+static gint smime_check_sig_async(MimeInfo *mimeinfo,
+	GCancellable *cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data)
 {
-	PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy;
-	
-	cm_return_val_if_fail(data != NULL, g_strdup("Error"));
+	MimeInfo *parent;
+	gchar *boundary;
+
+	/* Detached signature with a boundary */
+	if (g_ascii_strcasecmp(mimeinfo->subtype, "pkcs7-mime") &&
+		g_ascii_strcasecmp(mimeinfo->subtype, "x-pkcs7-mime"))
+	{
+		parent = procmime_mimeinfo_parent(mimeinfo);
+		boundary = g_hash_table_lookup(parent->typeparameters, "boundary");
 
-	return sgpgme_sigstat_info_full(data->ctx, data->sigstatus);
+		if (boundary == NULL) {
+			g_warning("Unexpected S/MIME format subtype:%s without a boundary",
+				mimeinfo->subtype);
+			return -1;
+		}
+
+		return cm_check_detached_sig_async(mimeinfo,
+			cancellable,
+			callback,
+			user_data,
+			GPGME_PROTOCOL_CMS,
+			get_canonical_content);
+
+	/* Opaque pkcs7-mime blob with smime-type=signed-data */
+	} else {
+		return check_pkcs7_mime_sig(mimeinfo, cancellable, callback, user_data);
+	}
 }
 
 static gboolean smime_is_encrypted(MimeInfo *mimeinfo)
@@ -410,6 +550,7 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
 	gpgme_error_t err;
 	gchar *chars;
 	size_t len;
+	SignatureData *sig_data = NULL;
 
 	cm_return_val_if_fail(smime_is_encrypted(mimeinfo), NULL);
 	
@@ -434,10 +575,18 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
 	
 	plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx);
 
+	if (sigstat != NULL && sigstat->signatures != NULL) {
+		sig_data = g_new0(SignatureData, 1);
+		sig_data->status = sgpgme_sigstat_gpgme_to_privacy(ctx, sigstat);
+		sig_data->info_short = sgpgme_sigstat_info_short(ctx, sigstat);
+		sig_data->info_full = sgpgme_sigstat_info_full(ctx, sigstat);
+	}
+
+	gpgme_release(ctx);
 	gpgme_data_release(cipher);
 	if (plain == NULL) {
 		debug_print("plain is null!\n");
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -448,9 +597,9 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         	FILE_OP_ERROR(fname, "claws_fopen");
         	g_free(fname);
         	gpgme_data_release(plain);
-		gpgme_release(ctx);
 		debug_print("can't open!\n");
 		privacy_set_error(_("Couldn't open temporary file"));
+		privacy_free_signature_data(sig_data);
 		return NULL;
     	}
 
@@ -459,9 +608,9 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         	g_free(fname);
 		claws_fclose(dstfp);
         	gpgme_data_release(plain);
-		gpgme_release(ctx);
 		debug_print("can't close!\n");
 		privacy_set_error(_("Couldn't write to temporary file"));
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -474,9 +623,9 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         		g_free(fname);
         		g_free(chars);
         		gpgme_data_release(plain);
-			gpgme_release(ctx);
 			debug_print("can't write!\n");
 			privacy_set_error(_("Couldn't write to temporary file"));
+			privacy_free_signature_data(sig_data);
 			return NULL;
 		}
 	}
@@ -485,9 +634,9 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
         	g_free(fname);
        		g_free(chars);
         	gpgme_data_release(plain);
-		gpgme_release(ctx);
 		debug_print("can't close!\n");
 		privacy_set_error(_("Couldn't close temporary file"));
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	g_free(chars);
@@ -496,14 +645,14 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
 	g_free(fname);
 	if (parseinfo == NULL) {
 		privacy_set_error(_("Couldn't parse decrypted file."));
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 	decinfo = g_node_first_child(parseinfo->node) != NULL ?
 		g_node_first_child(parseinfo->node)->data : NULL;
 	if (decinfo == NULL) {
 		privacy_set_error(_("Couldn't parse decrypted file parts."));
-		gpgme_release(ctx);
+		privacy_free_signature_data(sig_data);
 		return NULL;
 	}
 
@@ -512,28 +661,24 @@ static MimeInfo *smime_decrypt(MimeInfo *mimeinfo)
 
 	decinfo->tmp = TRUE;
 
-	if (sigstat != NULL && sigstat->signatures != NULL) {
+	if (sig_data != NULL) {
 		if (decinfo->privacy != NULL) {
 			data = (PrivacyDataPGP *) decinfo->privacy;
 		} else {
 			data = smime_new_privacydata();
 			if (!data) {
-				gpgme_release(ctx);
 				return NULL;
 			}
 			decinfo->privacy = (PrivacyData *) data;	
 		}
-		data->done_sigtest = TRUE;
-		data->is_signed = TRUE;
-		data->sigstatus = sigstat;
-		if (data->ctx)
-			gpgme_release(data->ctx);
-		data->ctx = ctx;
-	} else
-		gpgme_release(ctx);
-	
-	
-	
+
+		if (data != NULL) {
+			data->done_sigtest = TRUE;
+			data->is_signed = TRUE;
+			decinfo->sig_data = sig_data;
+		}
+	}
+
 	return decinfo;
 }
 
@@ -803,6 +948,8 @@ gboolean smime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	fp = claws_fopen(tmpfile, "wb");
 	if (fp == NULL) {
 		FILE_OP_ERROR(tmpfile, "create");
+		for (gint x = 0; x < i; x++)
+			gpgme_key_unref(kset[x]);
 		g_free(kset);
 		g_free(tmpfile);
 		return FALSE;
@@ -815,6 +962,8 @@ gboolean smime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	fp = claws_fopen(tmpfile, "rb");
 	if (fp == NULL) {
 		FILE_OP_ERROR(tmpfile, "open");
+		for (gint x = 0; x < i; x++)
+			gpgme_key_unref(kset[x]);
 		g_free(kset);
 		g_free(tmpfile);
 		return FALSE;
@@ -834,6 +983,8 @@ gboolean smime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data)
 	gpgme_op_encrypt(ctx, kset, GPGME_ENCRYPT_ALWAYS_TRUST, gpgtext, gpgenc);
 
 	gpgme_release(ctx);
+	for (gint x = 0; x < i; x++)
+		gpgme_key_unref(kset[x]);
 	g_free(kset);
 	enccontent = sgpgme_data_release_and_get_mem(gpgenc, &len);
 
@@ -887,10 +1038,7 @@ static PrivacySystem smime_system = {
 	smime_free_privacydata,	/* free_privacydata */
 
 	smime_is_signed,		/* is_signed(MimeInfo *) */
-	smime_check_signature,	/* check_signature(MimeInfo *) */
-	smime_get_sig_status,		/* get_sig_status(MimeInfo *) */
-	smime_get_sig_info_short,	/* get_sig_info_short(MimeInfo *) */
-	smime_get_sig_info_full,	/* get_sig_info_full(MimeInfo *) */
+	smime_check_sig_async,
 
 	smime_is_encrypted,		/* is_encrypted(MimeInfo *) */
 	smime_decrypt,			/* decrypt(MimeInfo *) */
diff --git a/src/privacy.c b/src/privacy.c
index 01b282a6b..a77e9a814 100644
--- a/src/privacy.c
+++ b/src/privacy.c
@@ -1,6 +1,6 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 Hiroyuki Yamamoto & the Claws Mail team
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
  *
  * 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
@@ -109,6 +109,25 @@ void privacy_free_privacydata(PrivacyData *privacydata)
 	system->free_privacydata(privacydata);
 }
 
+void privacy_free_signature_data(gpointer data)
+{
+	SignatureData *sig_data = (SignatureData *)data;
+
+	g_free(sig_data->info_short);
+	g_free(sig_data->info_full);
+	g_free(sig_data);
+}
+
+void privacy_free_sig_check_task_result(gpointer data)
+{
+	SigCheckTaskResult *result = (SigCheckTaskResult *)data;
+
+	privacy_free_signature_data(result->sig_data);
+	if (result->newinfo)
+		procmime_mimeinfo_free_all(&result->newinfo);
+	g_free(result);
+}
+
 /**
  * Check if a MimeInfo is signed with one of the available
  * privacy system. If a privacydata is set in the MimeInfo
@@ -193,26 +212,32 @@ void privacy_msginfo_get_signed_state(MsgInfo *msginfo, gchar **system)
  * \return Error code indicating the result of the check,
  *         < 0 if an error occurred
  */
-gint privacy_mimeinfo_check_signature(MimeInfo *mimeinfo)
+gint privacy_mimeinfo_check_signature(MimeInfo *mimeinfo,
+	GCancellable *cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data)
 {
 	PrivacySystem *system;
 
-	cm_return_val_if_fail(mimeinfo != NULL, -1);
+	if (mimeinfo == NULL)
+		g_error("siginfo was NULL");
+
+	if (mimeinfo->privacy == NULL) {
+		g_warning("mimeinfo->privacy was NULL");
 
-	if (mimeinfo->privacy == NULL)
 		privacy_mimeinfo_is_signed(mimeinfo);
-	
-	if (mimeinfo->privacy == NULL)
-		return -1;
-	
+		if (mimeinfo->privacy == NULL) {
+			g_error("failed to set up PrivacyData");
+		}
+	}
+
 	system = privacy_data_get_system(mimeinfo->privacy);
 	if (system == NULL)
-		return -1;
+		g_error("failed to get privacy system");
+	else if (system->check_signature == NULL)
+		g_error("didn't find check_signature function");
 
-	if (system->check_signature == NULL)
-		return -1;
-	
-	return system->check_signature(mimeinfo);
+	return system->check_signature(mimeinfo, cancellable, callback, user_data);
 }
 
 SignatureStatus privacy_mimeinfo_get_sig_status(MimeInfo *mimeinfo)
@@ -221,61 +246,49 @@ SignatureStatus privacy_mimeinfo_get_sig_status(MimeInfo *mimeinfo)
 
 	cm_return_val_if_fail(mimeinfo != NULL, -1);
 
-	if (mimeinfo->privacy == NULL)
+	if (mimeinfo->privacy == NULL) {
 		privacy_mimeinfo_is_signed(mimeinfo);
-	
-	if (mimeinfo->privacy == NULL)
-		return SIGNATURE_UNCHECKED;
-	
+
+		if (mimeinfo->privacy == NULL)
+			return SIGNATURE_UNCHECKED;
+	}
+
 	system = privacy_data_get_system(mimeinfo->privacy);
 	if (system == NULL)
 		return SIGNATURE_UNCHECKED;
-	if (system->get_sig_status == NULL)
+
+	if (mimeinfo->sig_data == NULL)
 		return SIGNATURE_UNCHECKED;
-	
-	return system->get_sig_status(mimeinfo);
+	else
+		return mimeinfo->sig_data->status;
 }
 
-gchar *privacy_mimeinfo_sig_info_short(MimeInfo *mimeinfo)
+gchar *privacy_mimeinfo_get_sig_info(MimeInfo *mimeinfo, gboolean full)
 {
 	PrivacySystem *system;
+	gchar *info;
 
 	cm_return_val_if_fail(mimeinfo != NULL, NULL);
 
-	if (mimeinfo->privacy == NULL)
+	if (mimeinfo->privacy == NULL) {
 		privacy_mimeinfo_is_signed(mimeinfo);
-	
-	if (mimeinfo->privacy == NULL)
-		return g_strdup(_("No signature found"));
-	
+
+		if (mimeinfo->privacy == NULL)
+			return _("No signature found");
+	}
+
 	system = privacy_data_get_system(mimeinfo->privacy);
 	if (system == NULL)
-		return g_strdup(_("No signature found"));
-	if (system->get_sig_info_short == NULL)
-		return g_strdup(_("No information available"));
-	
-	return system->get_sig_info_short(mimeinfo);
-}
+		return _("No signature found");
 
-gchar *privacy_mimeinfo_sig_info_full(MimeInfo *mimeinfo)
-{
-	PrivacySystem *system;
+	if (mimeinfo->sig_data == NULL)
+		return _("No information available");
 
-	cm_return_val_if_fail(mimeinfo != NULL, NULL);
+	info = full ? mimeinfo->sig_data->info_full : mimeinfo->sig_data->info_short;
+	if (info == NULL)
+		return _("No information available");
 
-	if (mimeinfo->privacy == NULL)
-		privacy_mimeinfo_is_signed(mimeinfo);
-	
-	if (mimeinfo->privacy == NULL)
-		return g_strdup(_("No signature found"));
-	
-	system = privacy_data_get_system(mimeinfo->privacy);
-	if (system == NULL)
-		return g_strdup(_("No signature found"));
-	if (system->get_sig_info_full == NULL)
-		return g_strdup(_("No information available"));
-	
-	return system->get_sig_info_full(mimeinfo);
+	return info;
 }
 
 gboolean privacy_mimeinfo_is_encrypted(MimeInfo *mimeinfo)
diff --git a/src/privacy.h b/src/privacy.h
index ebc191972..3aafae9ad 100644
--- a/src/privacy.h
+++ b/src/privacy.h
@@ -1,6 +1,6 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
  *
  * 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
@@ -30,9 +30,21 @@ typedef enum {
 	SIGNATURE_KEY_EXPIRED,
 	SIGNATURE_INVALID,
 	SIGNATURE_CHECK_FAILED,
-	SIGNATURE_CHECK_TIMEOUT
+	SIGNATURE_CHECK_TIMEOUT,
+	SIGNATURE_CHECK_ERROR
 } SignatureStatus;
 
+typedef struct _SignatureData {
+	SignatureStatus status;
+	gchar *info_short;
+	gchar *info_full;
+} SignatureData;
+
+typedef struct _SigCheckTaskResult {
+	SignatureData *sig_data;
+	struct _MimeInfo *newinfo;
+} SigCheckTaskResult;
+
 #include <glib.h>
 
 #include "procmime.h"
@@ -42,13 +54,17 @@ void privacy_register_system			(PrivacySystem *system);
 void privacy_unregister_system			(PrivacySystem *system);
 
 void privacy_free_privacydata			(PrivacyData *);
+void privacy_free_signature_data		(gpointer);
+void privacy_free_sig_check_task_result	(gpointer);
 
 void privacy_msginfo_get_signed_state		(MsgInfo *, gchar **system);
 gboolean privacy_mimeinfo_is_signed		(MimeInfo *);
-gint privacy_mimeinfo_check_signature		(MimeInfo *);
+gint privacy_mimeinfo_check_signature	(MimeInfo *mimeinfo,
+	GCancellable *cancellable,
+	GAsyncReadyCallback callback,
+	gpointer user_data);
 SignatureStatus privacy_mimeinfo_get_sig_status	(MimeInfo *);
-gchar *privacy_mimeinfo_sig_info_short		(MimeInfo *);
-gchar *privacy_mimeinfo_sig_info_full		(MimeInfo *);
+gchar *privacy_mimeinfo_get_sig_info		(MimeInfo *, gboolean);
 
 gboolean privacy_mimeinfo_is_encrypted		(MimeInfo *);
 gint privacy_mimeinfo_decrypt			(MimeInfo *);
@@ -83,10 +99,10 @@ struct _PrivacySystem {
 	void		 (*free_privacydata)	(PrivacyData *data);
 
 	gboolean	 (*is_signed)		(MimeInfo *mimeinfo);
-	gint		 (*check_signature)	(MimeInfo *mimeinfo);
-	SignatureStatus	 (*get_sig_status)	(MimeInfo *mimeinfo);
-	gchar		*(*get_sig_info_short)	(MimeInfo *mimeinfo);
-	gchar		*(*get_sig_info_full)	(MimeInfo *mimeinfo);
+	gint		 (*check_signature)	(MimeInfo *mimeinfo,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
 
 	gboolean	 (*is_encrypted)	(MimeInfo *mimeinfo);
 	MimeInfo	*(*decrypt)		(MimeInfo *mimeinfo);
diff --git a/src/procmime.c b/src/procmime.c
index 64c7af29d..7e58aa9f7 100644
--- a/src/procmime.c
+++ b/src/procmime.c
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2021 the Claws Mail Team and Hiroyuki Yamamoto
+ * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
  *
  * 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
@@ -144,6 +144,9 @@ static gboolean free_func(GNode *node, gpointer data)
 	if (mimeinfo->privacy)
 		privacy_free_privacydata(mimeinfo->privacy);
 
+	if (mimeinfo->sig_data)
+		privacy_free_signature_data(mimeinfo->sig_data);
+
 	g_free(mimeinfo);
 
 	return FALSE;
diff --git a/src/procmime.h b/src/procmime.h
index e87a27624..8b6859f9b 100644
--- a/src/procmime.h
+++ b/src/procmime.h
@@ -1,6 +1,6 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
  *
  * 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
@@ -29,6 +29,7 @@
 
 #include "utils.h"
 #include "proctypes.h"
+#include "privacy.h"
 typedef enum
 {
 	ENC_7BIT,
@@ -149,6 +150,8 @@ struct _MimeInfo
 
 	/* Privacy */
 	struct _PrivacyData	*privacy;
+	GTask *last_sig_check_task;
+	SignatureData *sig_data;
 
 	gboolean	 broken;
 };

commit b52781b8c44a3796d6f5c0b8d33a386938cf6164
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Mon Sep 27 01:37:12 2021 -0700

    Remove cm_mutex_new/_free wrappers

diff --git a/src/common/utils.c b/src/common/utils.c
index 73c90393a..f741c62d5 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -4441,17 +4441,6 @@ size_t fast_strftime(gchar *buf, gint buflen, const gchar *format, struct tm *lt
 #define WEXITSTATUS(x) (x)
 #endif
 
-GMutex *cm_mutex_new(void) {
-	GMutex *m = g_new0(GMutex, 1);
-	g_mutex_init(m);
-	return m;
-}
-
-void cm_mutex_free(GMutex *mutex) {
-	g_mutex_clear(mutex);
-	g_free(mutex);
-}
-
 static gchar *canonical_list_to_file(GSList *list)
 {
 	GString *result = g_string_new(NULL);
diff --git a/src/common/utils.h b/src/common/utils.h
index f908114e3..7b8ed25ac 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -524,9 +524,6 @@ gboolean file_is_email(const gchar *filename);
 gboolean sc_g_list_bigger(GList *list, gint max);
 gboolean sc_g_slist_bigger(GSList *list, gint max);
 
-GMutex *cm_mutex_new(void);
-void cm_mutex_free(GMutex *mutex);
-
 int cm_canonicalize_filename(const gchar *filename, gchar **canonical_name);
 
 guchar *g_base64_decode_zero(const gchar *text, gsize *out_len);
diff --git a/src/compose.c b/src/compose.c
index 94ef48696..2c90fb85b 100644
--- a/src/compose.c
+++ b/src/compose.c
@@ -7818,7 +7818,7 @@ static Compose *compose_create(PrefsAccount *account,
 	compose->account = account;
 	compose->folder = folder;
 	
-	compose->mutex = cm_mutex_new();
+	g_mutex_init(&compose->mutex);
 	compose->set_cursor_pos = -1;
 
 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "compose");
@@ -9242,7 +9242,7 @@ static void compose_destroy(Compose *compose)
 	gtk_widget_destroy(compose->window);
 	toolbar_destroy(compose->toolbar);
 	g_free(compose->toolbar);
-	cm_mutex_free(compose->mutex);
+	g_mutex_clear(&compose->mutex);
 	g_free(compose);
 }
 
@@ -10320,7 +10320,7 @@ gboolean compose_draft (gpointer data, guint action)
 	draft = account_get_special_folder(compose->account, F_DRAFT);
 	cm_return_val_if_fail(draft != NULL, FALSE);
 	
-	if (!g_mutex_trylock(compose->mutex)) {
+	if (!g_mutex_trylock(&compose->mutex)) {
 		/* we don't want to lock the mutex once it's available,
 		 * because as the only other part of compose.c locking
 		 * it is compose_close - which means once unlocked,
@@ -10461,12 +10461,12 @@ warn_err:
 					  FALSE, NULL, ALERT_QUESTION);
 				if (val == G_ALERTALTERNATE) {
 					lock = FALSE;
-					g_mutex_unlock(compose->mutex); /* must be done before closing */
+					g_mutex_unlock(&compose->mutex); /* must be done before closing */
 					compose_close(compose);
 					return TRUE;
 				} else {
 					lock = FALSE;
-					g_mutex_unlock(compose->mutex); /* must be done before closing */
+					g_mutex_unlock(&compose->mutex); /* must be done before closing */
 					return FALSE;
 				}
 			}
@@ -10501,7 +10501,7 @@ warn_err:
 	
 	if (action == COMPOSE_QUIT_EDITING || action == COMPOSE_DRAFT_FOR_EXIT) {
 		lock = FALSE;
-		g_mutex_unlock(compose->mutex); /* must be done before closing */
+		g_mutex_unlock(&compose->mutex); /* must be done before closing */
 		compose_close(compose);
 		return TRUE;
 	} else {
@@ -10567,7 +10567,7 @@ warn_err:
 	}
 unlock:
 	lock = FALSE;
-	g_mutex_unlock(compose->mutex);
+	g_mutex_unlock(&compose->mutex);
 	return TRUE;
 }
 
@@ -10744,7 +10744,7 @@ static void compose_close_cb(GtkAction *action, gpointer data)
 
 	if (compose->modified) {
 		gboolean reedit = (compose->rmode == COMPOSE_REEDIT);
-		if (!g_mutex_trylock(compose->mutex)) {
+		if (!g_mutex_trylock(&compose->mutex)) {
 			/* we don't want to lock the mutex once it's available,
 			 * because as the only other part of compose.c locking
 			 * it is compose_close - which means once unlocked,
@@ -10763,7 +10763,7 @@ static void compose_close_cb(GtkAction *action, gpointer data)
 				 _("_Don't save"), _("_Save to Drafts"), GTK_STOCK_CANCEL,
 				 ALERTFOCUS_SECOND);
 		}
-		g_mutex_unlock(compose->mutex);
+		g_mutex_unlock(&compose->mutex);
 		switch (val) {
 		case G_ALERTDEFAULT:
 			if (compose_can_autosave(compose) && !reedit)
@@ -12128,7 +12128,7 @@ gboolean compose_close(Compose *compose)
 
 	cm_return_val_if_fail(compose, FALSE);
 
-	if (!g_mutex_trylock(compose->mutex)) {
+	if (!g_mutex_trylock(&compose->mutex)) {
 		/* we have to wait for the (possibly deferred by auto-save)
 		 * drafting to be done, before destroying the compose under
 		 * it. */
@@ -12152,7 +12152,7 @@ gboolean compose_close(Compose *compose)
 		prefs_common.compose_x = x;
 		prefs_common.compose_y = y;
 	}
-	g_mutex_unlock(compose->mutex);
+	g_mutex_unlock(&compose->mutex);
 	compose_destroy(compose);
 	return FALSE;
 }
diff --git a/src/compose.h b/src/compose.h
index 3c155be55..7b7fb0154 100644
--- a/src/compose.h
+++ b/src/compose.h
@@ -244,7 +244,7 @@ struct _Compose
 	GtkTextTag *uri_tag;
 
 	gboolean automatic_break;
-	GMutex *mutex;
+	GMutex mutex;
 	gint close_timeout_tag;
 	gchar *orig_charset;
 	gint set_cursor_pos;
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 09e6d031b..b1dd0ccb4 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -4259,8 +4259,8 @@ static gboolean sslcert_get_client_cert_hook(gpointer source, gpointer data)
 }
 
 struct GetPassData {
-	GCond *cond;
-	GMutex* mutex;
+	GCond cond;
+	GMutex mutex;
 	gchar **pass;
 };
 
@@ -4268,30 +4268,28 @@ struct GetPassData {
 static gboolean do_get_pass(gpointer data)
 {
 	struct GetPassData *pass_data = (struct GetPassData *)data;
-	g_mutex_lock(pass_data->mutex);
+	g_mutex_lock(&pass_data->mutex);
 	*(pass_data->pass) = input_dialog_query_password("the PKCS12 client certificate", NULL);
-	g_cond_signal(pass_data->cond);
-	g_mutex_unlock(pass_data->mutex);
+	g_cond_signal(&pass_data->cond);
+	g_mutex_unlock(&pass_data->mutex);
 	return FALSE;
 }
 static gboolean sslcert_get_password(gpointer source, gpointer data)
 { 
 	struct GetPassData pass_data;
 	/* do complicated stuff to be able to call GTK from the mainloop */
-	pass_data.cond = g_new0(GCond, 1);
-	g_cond_init(pass_data.cond);
-	pass_data.mutex = cm_mutex_new();
+	g_cond_init(&pass_data.cond);
+	g_mutex_init(&pass_data.mutex);
 	pass_data.pass = (gchar **)source;
 
-	g_mutex_lock(pass_data.mutex);
+	g_mutex_lock(&pass_data.mutex);
 
 	g_idle_add(do_get_pass, &pass_data);
 
-	g_cond_wait(pass_data.cond, pass_data.mutex);
-	g_cond_clear(pass_data.cond);
-	g_free(pass_data.cond);
-	g_mutex_unlock(pass_data.mutex);
-	cm_mutex_free(pass_data.mutex);
+	g_cond_wait(&pass_data.cond, &pass_data.mutex);
+	g_cond_clear(&pass_data.cond);
+	g_mutex_unlock(&pass_data.mutex);
+	g_mutex_clear(&pass_data.mutex);
 
 	return TRUE;
 }

commit 6596986bb6f093716c38f9af25f5771a88b6747a
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Mon Sep 27 00:31:11 2021 -0700

    Remove slist_copy_deep wrapper

diff --git a/src/addrduplicates.c b/src/addrduplicates.c
index 06def3d6a..02236304f 100644
--- a/src/addrduplicates.c
+++ b/src/addrduplicates.c
@@ -272,7 +272,7 @@ static gint collect_emails(ItemPerson *itemperson, AddressDataSource *ds)
 		addr = g_utf8_strdown(email->address, -1);
 		old_val = g_hash_table_lookup(addr_hash, addr);
 		if(old_val)
-			new_val = slist_copy_deep(old_val, (GCopyFunc)copy_hash_val);
+			new_val = g_slist_copy_deep(old_val, (GCopyFunc)copy_hash_val, NULL);
 		else
 			new_val = NULL;
 
diff --git a/src/common/utils.c b/src/common/utils.c
index 070af31fc..73c90393a 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -93,11 +93,6 @@
 
 static gboolean debug_mode = FALSE;
 
-GSList *slist_copy_deep(GSList *list, GCopyFunc func)
-{
-	return g_slist_copy_deep(list, func, NULL);
-}
-
 void list_free_strings_full(GList *list)
 {
 	g_list_free_full(list, (GDestroyNotify)g_free);
diff --git a/src/common/utils.h b/src/common/utils.h
index 55909d588..f908114e3 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -248,11 +248,6 @@ gboolean debug_get_mode		(void);
 #define Str(x)	#x
 #define Xstr(x)	Str(x)
 
-/* List utilities. */
-
-GSList *slist_copy_deep		(GSList		*list,
-				 GCopyFunc	 func);
-
 /* String utilities.  */
 
 void list_free_strings_full		(GList		*list);
diff --git a/src/procmsg.c b/src/procmsg.c
index 4c7efb5e3..063818a7d 100644
--- a/src/procmsg.c
+++ b/src/procmsg.c
@@ -1291,8 +1291,8 @@ MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo)
 	if (msginfo->extradata) {
 		newmsginfo->extradata = g_new0(MsgInfoExtraData, 1);
 		if (msginfo->extradata->avatars) {
-			newmsginfo->extradata->avatars = slist_copy_deep(msginfo->extradata->avatars,
-								(GCopyFunc) procmsg_msginfoavatar_copy);
+			newmsginfo->extradata->avatars = g_slist_copy_deep(msginfo->extradata->avatars,
+								(GCopyFunc) procmsg_msginfoavatar_copy, NULL);
 		}
 		MEMBDUP(extradata->dispositionnotificationto);
 		MEMBDUP(extradata->returnreceiptto);
@@ -1354,8 +1354,8 @@ MsgInfo *procmsg_msginfo_get_full_info_from_file(MsgInfo *msginfo, const gchar *
 		if (!msginfo->extradata->list_owner)
 			msginfo->extradata->list_owner = g_strdup(full_msginfo->extradata->list_owner);
 		if (!msginfo->extradata->avatars)
-			msginfo->extradata->avatars = slist_copy_deep(full_msginfo->extradata->avatars,
-									(GCopyFunc) procmsg_msginfoavatar_copy);
+			msginfo->extradata->avatars = g_slist_copy_deep(full_msginfo->extradata->avatars,
+									(GCopyFunc) procmsg_msginfoavatar_copy, NULL);
 		if (!msginfo->extradata->dispositionnotificationto)
 			msginfo->extradata->dispositionnotificationto = 
 				g_strdup(full_msginfo->extradata->dispositionnotificationto);

commit 2608cac9b36213f5a519f2ed810b3210be0c03b9
Author: Jonathan Boeing <jonathan at claws-mail.org>
Date:   Mon Sep 27 00:22:26 2021 -0700

    Set minimum GLib version to 2.36

diff --git a/configure.ac b/configure.ac
index facf5d700..1b9886eb0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -466,7 +466,7 @@ dnl ** common code **
 dnl *****************
 
 dnl check for glib
-PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28 gmodule-2.0 >= 2.28 gobject-2.0 >= 2.28 gthread-2.0 >= 2.28])
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.36 gmodule-2.0 >= 2.36 gobject-2.0 >= 2.36 gthread-2.0 >= 2.36])
 
 GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
 AC_SUBST(GLIB_GENMARSHAL)
diff --git a/src/common/utils.c b/src/common/utils.c
index 0631f2afe..070af31fc 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -95,17 +95,7 @@ static gboolean debug_mode = FALSE;
 
 GSList *slist_copy_deep(GSList *list, GCopyFunc func)
 {
-#if GLIB_CHECK_VERSION(2, 34, 0)
 	return g_slist_copy_deep(list, func, NULL);
-#else
-	GSList *res = g_slist_copy(list);
-	GSList *walk = res;
-	while (walk) {
-		walk->data = func(walk->data, NULL);
-		walk = walk->next;
-	}
-	return res;
-#endif
 }
 
 void list_free_strings_full(GList *list)
@@ -4457,22 +4447,14 @@ size_t fast_strftime(gchar *buf, gint buflen, const gchar *format, struct tm *lt
 #endif
 
 GMutex *cm_mutex_new(void) {
-#if GLIB_CHECK_VERSION(2,32,0)
 	GMutex *m = g_new0(GMutex, 1);
 	g_mutex_init(m);
 	return m;
-#else
-	return g_mutex_new();
-#endif
 }
 
 void cm_mutex_free(GMutex *mutex) {
-#if GLIB_CHECK_VERSION(2,32,0)
 	g_mutex_clear(mutex);
 	g_free(mutex);
-#else
-	g_mutex_free(mutex);
-#endif
 }
 
 static gchar *canonical_list_to_file(GSList *list)
@@ -4664,40 +4646,6 @@ guchar *g_base64_decode_zero(const gchar *text, gsize *out_len)
 	return out;
 }
 
-#if !GLIB_CHECK_VERSION(2, 30, 0)
-/**
- * g_utf8_substring:
- * @str: a UTF-8 encoded string
- * @start_pos: a character offset within @str
- * @end_pos: another character offset within @str
- *
- * Copies a substring out of a UTF-8 encoded string.
- * The substring will contain @end_pos - @start_pos
- * characters.
- *
- * Returns: a newly allocated copy of the requested
- *     substring. Free with g_free() when no longer needed.
- *
- * Since: GLIB 2.30
- */
-gchar *
-g_utf8_substring (const gchar *str,
-				  glong 	   start_pos,
-				  glong 	   end_pos)
-{
-  gchar *start, *end, *out;
-
-  start = g_utf8_offset_to_pointer (str, start_pos);
-  end = g_utf8_offset_to_pointer (start, end_pos - start_pos);
-
-  out = g_malloc (end - start + 1);
-  memcpy (out, start, end - start);
-  out[end - start] = 0;
-
-  return out;
-}
-#endif
-
 /* Attempts to read count bytes from a PRNG into memory area starting at buf.
  * It is up to the caller to make sure there is at least count bytes
  * available at buf. */
diff --git a/src/common/utils.h b/src/common/utils.h
index 4b1b42219..55909d588 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -536,12 +536,6 @@ int cm_canonicalize_filename(const gchar *filename, gchar **canonical_name);
 
 guchar *g_base64_decode_zero(const gchar *text, gsize *out_len);
 
-#if !GLIB_CHECK_VERSION(2, 30, 0)
-gchar   *g_utf8_substring         (const gchar *p,
-                                   glong        start_pos,
-                                   glong        end_pos) G_GNUC_MALLOC;
-#endif
-
 gboolean get_random_bytes(void *buf, size_t count);
 
 #ifdef __cplusplus
diff --git a/src/main.c b/src/main.c
index fab75e8df..4d869457e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1136,10 +1136,6 @@ int main(int argc, char *argv[])
 	
 	if (cmd.exit)
 		return 0;
-#if !GLIB_CHECK_VERSION(2,32,0)
-	if (!g_thread_supported())
-		g_thread_init(NULL);
-#endif
 
 	reset_statistics();
 	
@@ -1199,12 +1195,6 @@ int main(int argc, char *argv[])
 	/* Create container for all the menus we will be adding */
 	MENUITEM_ADDUI("/", "Menus", NULL, GTK_UI_MANAGER_MENUBAR);
 
-#if !GLIB_CHECK_VERSION(2,32,0)
-	if (!g_thread_supported()) {
-		g_error("g_thread is not supported by glib");
-	}
-#endif
-
 #ifdef G_OS_WIN32
 	CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_home_dir(), 1, win32_close_log(););
 #else
diff --git a/src/plugins/notification/notification_plugin.c b/src/plugins/notification/notification_plugin.c
index ef27d39ee..fcd9b85e6 100644
--- a/src/plugins/notification/notification_plugin.c
+++ b/src/plugins/notification/notification_plugin.c
@@ -220,14 +220,6 @@ gint plugin_init(gchar **error)
 			   VERSION_NUMERIC, _("Notification"), error))
     return -1;
 
-#if !GLIB_CHECK_VERSION(2,32,0)
-  /* Check if threading is enabled */
-  if(!g_thread_supported()) {
-    *error = g_strdup(_("The Notification plugin needs threading support."));
-    return -1;
-  }
-#endif
-
   hook_f_item = hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST,
 				    my_folder_item_update_hook, NULL);
   if(hook_f_item == 0) {
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 790b2c8c5..09e6d031b 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -4278,12 +4278,8 @@ static gboolean sslcert_get_password(gpointer source, gpointer data)
 { 
 	struct GetPassData pass_data;
 	/* do complicated stuff to be able to call GTK from the mainloop */
-#if !GLIB_CHECK_VERSION(2,32,0)
-	pass_data.cond = g_cond_new();
-#else
 	pass_data.cond = g_new0(GCond, 1);
 	g_cond_init(pass_data.cond);
-#endif
 	pass_data.mutex = cm_mutex_new();
 	pass_data.pass = (gchar **)source;
 
@@ -4292,12 +4288,8 @@ static gboolean sslcert_get_password(gpointer source, gpointer data)
 	g_idle_add(do_get_pass, &pass_data);
 
 	g_cond_wait(pass_data.cond, pass_data.mutex);
-#if !GLIB_CHECK_VERSION(2,32,0)
-	g_cond_free(pass_data.cond);
-#else
 	g_cond_clear(pass_data.cond);
 	g_free(pass_data.cond);
-#endif
 	g_mutex_unlock(pass_data.mutex);
 	cm_mutex_free(pass_data.mutex);
 

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list