[Commits] [SCM] claws branch, gtk3, updated. 4.0.0-343-g617596d53

jonathan at claws-mail.org jonathan at claws-mail.org
Fri Oct 29 15:45:40 CET 2021


The branch, gtk3 has been updated
       via  617596d534c39e1d523bccb2d0019b23bfce17c4 (commit)
       via  1559337f7c5b42a54e824cf21bd39835998c5a35 (commit)
       via  6df5a3adb6da715fa136a41c4f81ce4c2b079c27 (commit)
       via  78de2d36bee076116e2ce45f55318ddfe81d5d1b (commit)
      from  5082e914b7afdc9b211ae0c4cc0347f8a933e0ad (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                                 | 393 +++++++-----------
 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              | 318 +++++++++------
 src/plugins/pgpinline/plugin.c                 |   2 +-
 src/plugins/pgpmime/claws.def                  |   7 +-
 src/plugins/pgpmime/mypgpcore.def              |   7 +-
 src/plugins/pgpmime/pgpmime.c                  | 211 +++-------
 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                      | 534 ++++++++++++++++---------
 src/prefs_account.c                            |  34 +-
 src/privacy.c                                  | 115 +++---
 src/privacy.h                                  |  36 +-
 src/procmime.c                                 |   5 +-
 src/procmime.h                                 |   7 +-
 src/procmsg.c                                  |   8 +-
 32 files changed, 1153 insertions(+), 986 deletions(-)


- Log -----------------------------------------------------------------
commit 617596d534c39e1d523bccb2d0019b23bfce17c4
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 eb25edb1d..c57dd1617 100644
--- a/src/mimeview.c
+++ b/src/mimeview.c
@@ -557,26 +557,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
 	}
 }
 
@@ -591,20 +576,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)
@@ -998,6 +982,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));
@@ -1035,21 +1032,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:
@@ -1077,6 +1073,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");
@@ -1086,19 +1083,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);
 
@@ -1106,13 +1101,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,
@@ -1125,242 +1132,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);
 	}
 }
 
@@ -1381,11 +1275,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,
@@ -1434,7 +1325,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);
 }
 
@@ -2637,6 +2528,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,
@@ -2656,7 +2548,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);		
@@ -2706,7 +2598,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 d7f3b7cd4..7d5f8ccac 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;
@@ -101,9 +82,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 974531dc9..055d14242 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 4e7312320..1d1775d35 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 fe11fa107..ed5ce6ee4 100644
--- a/src/plugins/pgpinline/claws.def
+++ b/src/plugins/pgpinline/claws.def
@@ -14,6 +14,8 @@ debug_srcname
 file_read_stream_to_str_no_recode
 get_mime_tmp_dir
 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 c467f86d3..bf25bf29f 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 f2b6f0276..3fb902ea1 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 bbd25975f..d29d1b319 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 36cda8046..dfb78b59c 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 1559337f7c5b42a54e824cf21bd39835998c5a35
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 4358eff0b..f8b5262f7 100644
--- a/src/compose.c
+++ b/src/compose.c
@@ -7795,7 +7795,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");
@@ -9212,7 +9212,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);
 }
 
@@ -10288,7 +10288,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,
@@ -10429,12 +10429,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;
 				}
 			}
@@ -10469,7 +10469,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 {
@@ -10535,7 +10535,7 @@ warn_err:
 	}
 unlock:
 	lock = FALSE;
-	g_mutex_unlock(compose->mutex);
+	g_mutex_unlock(&compose->mutex);
 	return TRUE;
 }
 
@@ -10712,7 +10712,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,
@@ -10731,7 +10731,7 @@ static void compose_close_cb(GtkAction *action, gpointer data)
 				 _("_Don't save"), _("_Save to Drafts"), _("_Cancel"),
 				 ALERTFOCUS_SECOND);
 		}
-		g_mutex_unlock(compose->mutex);
+		g_mutex_unlock(&compose->mutex);
 		switch (val) {
 		case G_ALERTDEFAULT:
 			if (compose_can_autosave(compose) && !reedit)
@@ -12094,7 +12094,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. */
@@ -12118,7 +12118,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 011da35b0..0da46906b 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 991969a22..76d8351d0 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -4209,8 +4209,8 @@ static gboolean sslcert_get_client_cert_hook(gpointer source, gpointer data)
 }
 
 struct GetPassData {
-	GCond *cond;
-	GMutex* mutex;
+	GCond cond;
+	GMutex mutex;
 	gchar **pass;
 };
 
@@ -4218,30 +4218,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 6df5a3adb6da715fa136a41c4f81ce4c2b079c27
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 05e619c7d..6e7e8e3f2 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 78de2d36bee076116e2ce45f55318ddfe81d5d1b
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 7a60bff00..3628ade8e 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 419b132aa..f4a722b83 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1140,10 +1140,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();
 	
@@ -1183,12 +1179,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 e9151bd1a..d946a2eca 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 911186858..991969a22 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -4228,12 +4228,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;
 
@@ -4242,12 +4238,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